Paul M. Jones

Don't listen to the crowd, they say "jump."

There Is No Such Thing As "Multi-Tasking"

The last time I wrote about Dirk Karkles, we learned that "do your best" is not a managerial plan of action.

Dirk Karkles thinks he can pay attention to more than one thing at a time. For example, he thinks he can write a report and carry on a phone conversation (or an IM/IRC session) at the same time. "I'm multi-tasking!" he says, sometimes with pride.

To this I say: There is no such thing as multi-tasking, there is only attention-switching.

You cannot perform two or more non-trivial tasks at the same time; at best, you pay attention to one and mostly ignore the other, then you switch your attention to the other and dismiss the first one temporarily, and then you switch your attention back to the first again. This is far less effective than completing the first task, then moving on to the second task, because of the time and mental effort it takes to switch between tasks.

Attention-switching is particularly bad when you are in real-time or near-real-time conversation. If you are doing other things while talking with someone else by voice or IM/IRC, you're telling the other person they are not worth your full attention. If they're not worth your attention, why are you worth theirs? ("I'm the boss" and "I'm paying them" and variations thereupon are not valid arguments -- try again.) You are wasting your time, and theirs, by not being a full participant in the conversation.

Now, there are times when you must give your attention to multiple tasks. Be aware that you are not multi-tasking, you are attention-switching, and take this into account when you switch your attention to another task. At the very least, you will need to take time to "catch up" on the task before you perform some new action related to it. For example, in an IM/IRC conversation that you are taking active part in, you will need to read and comprehend the backlog of messages before you you can even think about writing a meaningful response. Among other things, this means that attention-switching is not a net time saver, it is a net time spender -- but sometimes you have no other option.

So, the next time some tells you "I'm multi-tasking!" you know that person is not paying full attention to anything he's doing right then. Similarly, if you find yourself attention-switching in live conversation, have the common courtesy to excuse yourself and pick back up again later, when you can give it your full attention. "Multi-tasking" is something to apologize for, not to be proud of.


Host Switch

Quick note to say I'm moving my blog from Pair.com to my new WebFaction space. Layouts, etc. will be different until I copy over themes and other images.


What Does This Say About Unit-Testing in PHP Land?

Without having done actual research, and depending on my personal experience alone, I would assert that in PHP userland ...

  • There are maybe 20 or more general-purpose CMSes.
  • There are perhaps 50 or more public frameworks (of varying quality and approach).
  • There are easily 100 or more templating libraries (even if most of them can be grouped under 4 or 5 approaches).
  • There appear to be only 5 unit-test systems: PhpUnit, SimpleTest, Solar_Test, PHPT, and Lime.

Dispute the specific numbers all you like; they're not the point. The point is that CMSes, frameworks, template systems, etc. seem to be a very common artifact among PHP developers, but writing (and then publishing) unit-test systems does not seem anywhere near as common an obsession.

What does this say, if anything, about the attention given to unit-testing among PHP developers?

Note that this is an *off-the-cuff opinion* and a *request for comment*, and nothing else. (Some folks get testy about testing; please remember to be nice while commenting. ;-)

Update: And there are only 3 or 4 documentation systems: PhpDocumentor, Doxygen, and Solar_Docs, along with the various combinations of DocBook tools that Zend, PEAR, and PHP are using. I wonder how that enters into it, if at all.


Dump TV, Get Rich

Those of you who know me well, know that I am not much of a TV watcher. What little I do watch is boring to most normal people; by way of example, note that my 10-year-old 25" RCA tube has the C-SPAN logo burned into the bottom right corner.

So for me, this article feels like vindication:

How Dumping TV Allowed Me To Quit My Job...

Not that I'm rich by any means, but you get the point -- TV is usually a soporific time-waster. Watch less TV, get more "real" stuff done.


Solar 1.0.0 alpha1 Released

After more months of breaks, changes, additions, and refactoring, I'm (finallly) at the point where I'm ready to call the Solar framework for PHP 5 feature-complete. The first of this feature-complete series is the new Solar-1.0.0alpha1 release as of Sunday, 11 Nov, 2007. We now have at least 80% of everything you would need to build web-based and cli-based applications. This is a big milestone for the project.

The change notes, of course, are gigantically long, so they're on a separate page.

Read on for more highlights, especially about the new ORM system replacing the previous Solar_Sql_Table series.

Highlights

  • The new Solar_Controller_Console and Solar_Controller_Command classes are analagous to front and page controllers, respectively, for the command line. This means you can build CLI commands in Solar much the same as you build web apps.

  • The new Solar_Filter class combines validating and sanitizing. It uses a helper structure identical to Solar_View so you can add your own filter helper classes. It also comes with a filter-chain system for applying filters to arrays or structs of user input.

  • We've moved a lot of the core functions of the Solar arch-class to their own static classes: Solar_File, Solar_Dir, and Solar_Registry.

  • Lots of changes in the Solar_Sql package related to database portability. There are two removals here: we don't ship with Oracle or MS-SQL any more, only MySQL, PostgreSQL, and SQLite. These are not permanent removals; as soon as I can get systems to test on, I'll put Oracle and MS-SQL back in place with all the new SQL portability goodness.

New ORM System

The biggest set of changes, though, are that the venerable Solar_Sql_Table and its companions have been removed in favor of some new hotness: Solar_Sql_Model. The new model class is still table-based, but it now recognizes related tables using has-one, belongs-to, and has-many relationships. (Strictly speaking, we don't have "has-and-belongs-to-many"; we use "has-many-through" instead.) It features single-table inheritance, built-in filtering, automatic table creation, automatic form-processor generation, and lots of other goodies.

Along with the table-based model class, we also have Solar_Sql_Model_Record and Solar_Sql_Model_Collection classes to represent, respectively, individual records and collections of records. The record class allows you to add business logic on the individual rows and related rows returned by the model, so technically the record class is an ActiveRecord pattern implementation. (Note that this is not a Rails ActiveRecord.) Similarly, the collection class allows you to add logic on a set of records.

Oscar Merida has added a getting-started page about Solar_Sql_Model on the community wiki here: http://solarphp.org/wiki/tutorials/SettingUpModels.

Next Steps

The Model class is almost where I want it to be for a full stable release, but it still needs a bit of tweaking. Other than that, the only things left for Solar are building a more-complete suite of unit tests, and writing more narrative documentation. As the tests fill out and we get more user feedback, I'll be able to move to a beta, then quickly to an official stable release.

Many thanks to all the people who have helped with this release in one way or another (and in no particular order): Clay Loveless, Rodrigo Moraes, Antti Holvikari, Chris Cornutt, Jeff Surgeson, Robert Gonzalez, and all the others on the mailing lists and the IRC channel and who are noted in the change logs but whose names escape me now. Thanks guys!


DCPHP Next Week

I'm back from the Microsoft conference, and I'll do a short writeup on that later. In other news, I'm going to OmniTI world headquarters next week.

While I'm there I'll attend the DCPHP conference to give a presentation: framework and application benchmarking (Wed, 7 Nov, 10:30 am). Woohoo! :-)

UPDATE (2007-12-07): A PDF of the slides (for an earlier version) can be found here.


Microsoft Web Developer Summit 2007

I'm spending today and tomorrow in Redmond, at the invitation of Microsoft, with a bunch of other movers-and-shakers in the PHP world. Microsoft says they want to get our feedback on their offerings, and find out how to better interoperate with PHP. This should be fun and interesting. :-)


My First Car

My first car was a 1974 For Maverick "Grabber." Via Instapundit, I found some photos of my old vehicle.

http://mmb.maverick.to/gallery/showimage.php?i=3122&c=7

I still have dreams about that car -- not always good ones. No air conditioning, the seat belts didn't always work, and the suspension would vibrate terribly at around 70 mph. The cure for that, of course, was to drive 80 mph (or faster) and it smoothed right out. With a 302cc engine, it had plenty of power for that. What a ride for a 17-year-old. :-)



Memory Leaks With Objects in PHP 5

Wow, this entry is getting a lot of traffic from DZone and other places. If you like this post, be sure to check out New Year's Benchmarks for PHP framework comparisons, and the Solar Framework for PHP 5. Thanks for visiting!

One of the nice things about using a scripting language is that it automates garbage collection for you. You don't have to worry about releasing memory when you're done with your variables. As each variable passes out of scope, PHP frees that memory for you. If you want to, you can free the memory yourself using unset(), but usually you don't have to.

But there is at least one circumstance in which PHP will not free memory for you when you call unset(). Cf. http://bugs.php.net/bug.php?id=33595.

Problem

If you have two objects in circular reference, such as in a parent-child relationship, calling unset() on the parent object will not free the memory used for the parent reference in the child object. (Nor will the memory be freed when the parent object is garbage-collected.)

Confusing? Here's a script you can run to see it in action:

<?php
class Foo {
    function __construct()
    {
        $this->bar = new Bar($this);
    }
}

class Bar {
    function __construct($foo = null)
    {
        $this->foo = $foo;
    }
}

while (true) {
    $foo = new Foo();
    unset($foo);
    echo number_format(memory_get_usage()) . "n";
}
?>

Run that and watch your memory usage climb and climb, until memory runs out.

...
33,551,616
33,551,976
33,552,336
33,552,696
PHP Fatal error:  Allowed memory size of 33554432 bytes exhausted
(tried to allocate 16 bytes) in memleak.php on line 17

For most PHP developers this behavior is not likely to be a problem. However, if you use a lot of objects in parent-child relationships over a long-running script, you can run out of memory pretty quickly, especially if those objects are relatively large. I discovered this myself while testing some ORM-related pieces for Solar and it took me a couple days to figure it out -- hence this blog post. ;-)

Userland Solution

The bugs.php.net link above presents a solution, albeit inelegant and tedious. The "fix" is to call a destructor method before unsetting the object. The destructor method should clear out any internal parent object references, which will free the memory that would otherwise leak.

The "fixed" script looks like this:

<?php
class Foo {
    function __construct()
    {
        $this->bar = new Bar($this);
    }
    function __destruct()
    {
        unset($this->bar);
    }
}

class Bar {
    function __construct($foo = null)
    {
        $this->foo = $foo;
    }
}

while (true) {
    $foo = new Foo();
    $foo->__destruct();
    unset($foo);
    echo number_format(memory_get_usage()) . "n";
}
?>

Note the new Foo::__destruct() method and the call to $foo->__destruct() before unsetting. Now the script will run forever, showing you the amount of memory it uses (which never gets any bigger, thank goodness).

PHP Internals Solution?

Why does the memory leak occur? I am not wise in the ways of PHP internals, but it has something to do with reference counts. The refcount for the child $foo reference inside $bar does not get decremented when the parent $foo is unset, so PHP thinks the $foo object is still needed and doesn't release the memory for it ... or something like that. I am sure to be displaying my ignorance here, but the general idea is the same: a refcount is not decremented, so some memory never gets released.

I get from the bugs.php.net link above that modifying the garbage-collection process to check for this kind of issue would be a performance-killer, and what little I know about refcounts makes me think this is true.

Instead of changing the garbage-collection process, would it make sense to have unset() do some extra processing on the variable to look for internal objects and unset them too? (Or perhaps to call __destruct() on objects being unset?) Maybe a PHP internals person can comment here or elsewhere on the practicality and/or wisdom of such changes.

UPDATE: Martin Fjordvald notes in the comments that a patch from David Wang for garbage collection does exist and is under consideration. (Did I say "patch"? More like "whole sheet of cloth" -- it's huge. See the CVS checkout instructions at the end of that email.) Problem is that it didn't garner many votes for inclusion in 5.3. A nice compromise solution might be to have the unset() function call the __destruct() method of objects sent to it; that would seem intuitively appropriate here.