the beginnings of a long on DB related pattern discussion.
After a lot of silence caused by lot's of work (good, my bills are happy) and a continuous diversion into scheme, haskell, dylan and other interesting languages, I'm back into php speaking land. Funny feeling that. So here comes the beginning of something I've been continuously rubbing my (leftovers of) brains against.
copout This is not php specific, but since it discusses frequent problems occuring in php apps, I've labeled it with as php related as well. Makes it easier maintaining the site you see.
I have a problem with active record as a pattern. It is a logical one. Essentially it turn a (SQL) database row into an object. The class of the object represents the SQL table or view. Of course you can add behaviour to those classes and objects, i.e. activating those records.
All that is nice and dandy, but when you start talking about relations and constructing dynamically queries and corresponding objects, we start hitting the limitations of what I will call from now on the naive active record.
The problem is not trivial at all. It boils down to how to make peace between the host language type system (for example classes) and the SQL's dynamic compound types - the relations expressed as SELECT variants for example. It gets even harder when we decide to reverse the direction, so that we actulally want to update the database. Yuk! As though somebody actually does that!
warning I realised, late enough not to correct it, that I'm using a particular case of wishful thinking - using any php callable in $callable(...) expressions. The reality is abit uglier. We need to use either
call_user_func($callable,...); call_user_func_array($callable,...) How I wish php could do that out of the box, especially when it actually does it, just not in the short syntax. Anyone happy to hold my hand to do a php patch for that feature? I'm very unfamiliar with the internals, sorry.
notice As Jared notes in his comment calling functions/methods with $ in a lot of cases you can use $obj->$meth(...) instead of call_user_func($callable,...);. Indeed you can use the following code as part of the remedy
list($object,$method) = some_call()
$object->$method(...)
unfortunately this discriminates against functions, which are lighter to use than their method brethren
and a mention The above two used to live on the top pattern page until I moved them here
While reading, researching and experimenting for my macros project the terms in the title get mixed a lot. I'll try to summarise what is my understanding of a lot of the above. To be fair, most of these words are heavily overloaded with sometimes contradictory and or ovelapping meanings, so this short is only about my personal summary, no pretence for a general study or lit review.
Generic programming intuitevely corresponds to design patterns, or a tool to implement them. There should be a distinction between the functional or algorithmic side of the term and the structural or data (type) genericity.
Macros have (let's say) two main responsibilities - adding syntactic sugar and abstraction of common patterns. The syntactic sugar bit is something which probably should happen at compile time, at least in a weakly typed language like php. So I'll skip them. The abstraction of computation, well this is wat codified design patterns are. This is what function, classes and the rest of the things we read about and use usually do. To abstract a function in php there are at least two different strategies, probably more, but these two are effective in diametrically different situations. The first one is a combination of the ideas of generic functions (higher order functions) and partial evaluation. In code it can look something like:
class Fluenter
{
private $obj;
function __construct($obj)
{
$this->obj = $obj;
}
static function MakeFluent($obj)
{
if ($obj instanceof fluent)
return $obj;
else
return new fluenter($obj);
}
function __call($method, $args)
{
$result = call_user_func_array(array($this->obj, $method), $args);
if (is_null($result))
return $this;
else if (is_object($result) and ($result instanceof $fluent))
return $result;
else
throw new RuntimeException(
"Fluent::__call called method $method ".
"and expected a null return or a non-fluent object, ".
"got (".gettype($return).") $return instead.");
}
}
<php
class example {
private $ifs = array( 'sin', 'cos' );
function x( &$acc ) {
$acc['t'] += 1;
$acc['x'] = $acc['x'] + $this->ifs[ rand(0,1) ]( 1/ $acc['t'] );
return $this;
}
}
$ex = new example();
$something = array('t'=>0, 'x' => 0 );
$ex->x($something) -> x($something) -> x($something);
print 't: ' . $something['t'] . ' x: ' . $something['x'] . "\n";
?>
and when you run it:
vlado@cow:~/php design patterns$ php php accumulator_passing.php
t: 3 x:1.34692254127
vlado@cow:~/php design patterns$ php accumulator_passing.php
t: 3 x: 1.64809122021
vlado@cow:~/php design patterns$ php accumulator_passing.php
t: 3 x: 2.66401049301
class fluent_class {
var $state_var;
function self_next( $arg ) {
....
return $this;
}
function other_next( $arg ) {
....
return $this->another;
}
}
$obj = new fluent_class();
$obj->self_next(1)
->self_next(2)
->other_next(3)
->something_else(4);
Googles Summer of yawn. - Google's "Summer of Code" has started and they have announced a few PHP projects. Some of them look interesting and useful. However, I am going to pick apart one in particular, that to be honest, looks neither interesting or useful: The PHP Macro Preprocessor.
....
Why does the PHP Preprocessor need to be stuck in a world of #ifdefs and #includes? Instead of blindly copying what the C preprocessor does, why not focus on the languages strengths and deficiencies? The object system of PHP needs to be looked at, and see if it can be improved upon through a method of code transformation.
[sacrificial rabbit]
I sooo totally agree with Jonnay on this. In fact it is simply like reading my own thoughts, just put it better english, , ok, nearly. But what to do about it? I don't really know, I'm afraid I chicken out from digging into the guts of php. When I last looked there it was really scary.
I guess I'm on the down form my design pattern tantrum hit. I updated the collection so it now has about 20 of them, not all can be considered "officially" design patterns, but to be honest I don't really care. I'm very well aware that I ignore the existance of boundaries between design patterns, idioms, techniques, ... That is intentional. I like my rainbow coloured world and I want to keep it that way. If you disagree - just read the small script. My tanrum energy is over and I need to do work work. So the combing over the php design pattern collection will come later. For now enjoy, and have anger fits of your own.
Oh yes. I'm using a particular case of wishful thinking - using any php callable in $callable(...) expressions. The reality is a bit uglier. We need to use either call_user_func($callable,...); call_user_func_array($callable,...) How I wish php could do that out of the box, especially when it actually does it, just not in the short syntax. Anyone happy to hold my hand to do a php patch for that feature? I'm very unfamiliar with the internals, sorry.