Game On! 
First thing, each object needs to have a means of saying what it contains. We could use the line that ItemForSale->getAmount() will always get that item's "amount" value, or it could be ItemForSale->get('amount'). The latter leads to easier swaping between objects because there's no need to tie to a specific method.
I'm assuming we're talking PHP 5.0. Instead of requiring accessor methods for each property, why not start with the standard PHP property access mechanism?
PHP Code:
Interface DataSource {
function __get($property);
function __set($property, $value);
function __isset($property);
function __unset($property);
}
Let me defined a usecase that I think needs to be supported:
PHP Code:
class MyDatabaseConfiguration extends DataSourceSupport implements DataSource {
public $host = 'localhost';
public $database = 'myapp';
public $user = 'jeff';
public $password = 'secret';
}
It should be possible to define a trivial data object such as this without having to declare accessor methods for each property. Thus, I will defer discussion accessor methods until a later post. Remember that the interface is about how others see the object, not about how its implemented internally. With the proper adapters, it should be possible to adapt almost any object to the DataSource interface.
With either, there needs to be a means of introspection so outside code knows what is available (I'm thinking particularly the Mapper part of DataMapper in this case). Something along the lines of getAvailableProperties() or getDeclaredProperties()?
Excellent. Lets have some meta data description classes. I think it will help make the discussion easier to follow:
PHP Code:
interface PropertyInfo {
function getName();
}
interface DataSourceInfo {
function getClass();
function getPropertyInfo($property);
}
Note that I'm not saying how one would get a DataSourceInfo instance. I'm not sure that adding a getAvailableProperties() or getDataSourceInfo() method to the DataSource interface is necessarily a good idea because of the extra dependency. (The JavaBeans spec avoids doings this.)
Now, there are three kinds of properties: standard, read only and write only. So
PHP Code:
interface PropertyInfo {
function getName();
function isReadable();
function isWritable();
}
Since a property might not be defined, an we need an exception:
PHP Code:
class PropertyNotFoundException extends Exception {}
Either __get or __set could raise this exception. Its not unusual for a __set style method in PHP to add a property that does not exist. I don't think its possible to pick only one behavior for __set (add if not found or exception if not found), so I would suggest adding the ability to find out which behavior one might expect:
PHP Code:
interface DataSourceInfo {
function getClass();
function getPropertyInfo($property);
function canAddProperties();
}
__unset presents a problem. With some kinds of DataSources, it will not be possible to actually remove a property, instead one would probably set it to NULL. Thus, I think that __unset should do just that. Remove if it can, set to NULL if it can't. That means we need more meta-data to figure out which behavior to expect:
PHP Code:
interface DataSourceInfo {
function getClass();
function getPropertyInfo($property);
function canAddProperties();
function canRemoveProperties();
}
or alternatively, we need an exception for __unset to raise:
PHP Code:
class CannotRemovePropertyException extends Exception {}
Since __isset should match the isset function and return FALSE if the property exists but has a value of NULL, we should probably have a hasProperty method on the DataSource interface. I would also put an addProperty() on, just to be more explicit. Lets throw on a removeAllProperties, a setMany, and an import, too:
PHP Code:
Interface DataSource {
function __get($property);
function __set($property, $value);
function __isset($property);
function __unset($property);
function hasProperty($property);
function addProperty($property, $value);
function removeAllProperties();
function setMany($propertyValueList);
function import($propertyValueList);
}
setMany and import both take an array of the form array('property'=>'value'). The difference between setMany and import is that import does the equivalent of __unset on every pre-existing property that is not in the propertyValueList. In other words, import starts over from a blank slate.
I would favor hard tabs to soft - even though PEAR does it the other way - simply from a storage perspective. "\t" is faster to load and smaller to storage than " ".
At the risk of starting an bad tangental discusssion, Who cares about a few bytes these days? Spaces are the only technique that can preserve formatting regardless of the program displaying the text. (Think about things like cat blah.php on the command line and browsing source code via an html based CVS browser).
(I don't use php 5 oo on an everyday basis please correct and forgive any transgressions I may make
)
Bookmarks