Posted in
Blog :: PHP and patterns
Warning. Serious tech rantage ahead. Proceed with caution!
I've been feeling more and more limited by PHP lately. I keep on reading the Ruby on Rails (or DJango) propaganda and wishing I could program in a nice shiny language that smart people are writing about like all the other cool kids. When I feel this way, I remind myself that I've got very good reasons for sticking to PHP: I've got a lot of investment in my hand rolled CMS, my experience and intimate knowledge of the language, and I see the business case for doing your development work in a worse-is-better environment that has enormous market penetration. I mean, lets face it, linux/apache/mysql/php is the default hosting setup out there; ruby and (say) mod_python setups are certainly a little more exotic at the moment.
I also remind myself that I'm going to switch to PHP5 at some point soon and that will ameliorate some of the frustration (static class member variables! Woohoo!) Every now and then, though, something reminds me of the limitations surrounding my environment, and I get set off again. See, as I've mentioned before, it's not just the language itself that bugs me, its the patterns of behaviour in the community surrounding the tool that sometimes makes life hard. Let's face: there is a lot of very badly written php code out there. I should know. I've written some of it. One pattern of behaviour that really irritates me lately, however, is when I see "tutorials" or php programming lessons that are broken.
What do I mean by broken? How about a tutorial that purports to show you a concept but gets it exactly wrong? At the end of last month I saw a link to a tutorial that was supposed to demonstrate the singleton pattern (parenthetically, I'm assuming a lot of knowledge here, if you don't know what that means google for "design patterns" or read the "Design" section at phpPatterns.com for php specific take). Briefly, the singleton concept is that there is one canonical global object that is shared across a variety of classes. The reasons for the singleton pattern aren't as compelling in dynamic languages, but the concept is still somewhat useful. The problem, however, is that the sample code was returning copies of it's "one canonical object" instead of references, so it did not do exactly the thing it was trying to accomplish.
I emailed the author who responded nicely, but didn't get the tutorial amended, so I thought I'd drop a quick blog post with a link to a sample implementation that works. This is when the PHP community started to really irk me. Here's a singleton implemented in php by Harry Fuecks (proprietor of the now defunct phpPatterns.com I mentioned above and easily a better PHP programmer than I). His code gets it wrong. Here is another tutorial, hosted on Zend even, that gets it wrong! These were two of the top three hits on google when I searched for "php singleton pattern". Finally, to cap off my frustration, when I visited php.net to clarify a point or two I found an error in the online documentation (or at least an ambiguous wording).
Ok. I'm going to handle this positively. First! It may be that there has been a change in the way references are handled in php3 to php4 that affects this problem and if so I will very happily update this post to reflect that it isn't the fault of the various authors that their code no longer works. Second: following is a simple explanation of the problem and the implementation that I'm currently using.
<?php class a{ var $string = 'originalvalue'; function a() { print ("constructor\n"); } } function &singleton() { static $a; if(!isset($a)) $a = new a(); return($a); } $b = &singleton(); $b->string = 'changed'; $c = &singleton(); print($c->string); ?>
What is the output of this code? Since it implements the singleton pattern, it prints "constructor" once and when $c->string is printed, it outputs "changed". Tho whole point of the singleton function is that $c and $b end up referencing the same object. How is it that three different PHP coders messed up such a simple concept? Oh those pesky &'s. Notice that the singleton function has an & before it and notice that the assignment is = & instead of just "=". Take away either of those ampersands and the output changes to "originalvalue" because you start dealing with copies instead of references. (See php.net for the official word on this (and also note that it changes in php5)). So you guessed it, the three tutorials I listed above did not have their ampersands in the right places, hence they end up dealing with copies instead of references.
Ironically, my code shouldn't work, according to the online documentation. To quote php.net "Note: If you try to return a reference from a function with the syntax: return ($found_var); this will not work as you are attempting to return the result of an expression, and not a variable, by reference." So the line "return($a);" in my singleton function should be "return $a;" instead I think (although the docs do say only php>=4.4 throws a warning about this.)
Alright, I've vented enough. If I'm in error, please explain it to me (webmaster@metapundit.net). Stay tuned for another tech rant coming soon...
Update: in response to questions, the sample above works properly under PHP 4.3.10-15 on a Mepis (debian) linux box...
Update: the talented Derek Devries emails with agreement that the general state of PHP educational material on the web leaves something to be desired. He has a Singleton tutorial that not only does what it is supposed to do but also gives a useful example of when and where the singleton pattern is useful plus demonstrates how PHP5 makes this stuff easier. Looks like this is only one of a series, so go read them all...
Update: This is very late, but Jason Sweat also threw in his 2 cents in an email. He says he's trying to elevate the level of understanding of Design Patterns among PHP coders and has written a book to prove it. Check it out!
Posted on Aug 30th 2005, 12:00 AM