5/16/2008

PHP Reflections In Time

Reflection in PHP is a little clunky and I say that with the greatest of compassion.

First of all we have the standard function interface to all that is good, call_user_func, call_user_method, func_get_args, get_defined_functions and so on.

So you can imagine a call_user_func to start with and then when classes came in they added call_user_method that takes the instance as well (surmising the history, I don't have any facts).

   class Fred
{
public function someMethod()
{
echo "Hello World\n";
}
}

$fred = new Fred();
$fred->someMethod();

// OR

call_user_method("someMethod", $fred);


However, this method is deprecated, in preference to old call_user_function with different parameters.

   call_user_func(array($fred, "someMethod"));


Then there are the new class oriented evolution with ReflectionClass, ReflectionMethod, ReflectionProperty and so on.

   $method = new ReflectionMethod("Fred", "someMethod");
$method->invoke($fred);


It doesn't seem to bad but there are new problems. This fails because "someMethod" is private, even though the call is from the same class. There doesn't appear to be a way around this. You can not call private methods with the new Reflection classes.

   class Fred
{
private function someMethod()
{
echo "Hello World\n";
}

public function testInvoke()
{
$method = new ReflectionMethod(__CLASS__, "someMethod");
$method->invoke($this);
}
}

$fred = new Fred();
$fred->testInvoke();


This produces this error message:

Fatal error: Uncaught exception 'ReflectionException' with message 'Trying to invoke private method Fred::someMethod() from scope ReflectionMethod'


However, you can switch back to the old way of doing it like this:

    class Fred
{
private function someMethod()
{
echo "Hello World\n";
}

public function testInvoke()
{
call_user_func(array($this, "someMethod"));
}
}

$fred = new Fred();
$fred->testInvoke();


The same situation exists with the two forms of property access:

$prop = new ReflectionProperty("Fred", "property");
$prop->getValue($fred);

and

    $fred->$propertyName


This mix of old an new techniques is how PHP is today and there is not much we can do but to wrap the variations in our own classes so that we can stay as portable as possible across future versions.

PHP, First Impressions

It has been 3 months now since I started learning PHP, I have spent lots of time fixing an existing site and reading over the good and bad of the available open source PHP projects.

I would describe PHP as a function based language with object oriented dreams. PHP lives in the between world where functions rule and programmers try to work out how to make use of its new OO features.

These OO features are new and many are missing key functionality so this has to be looked at as the evolution of a language that isn't quite there yet. It has the functions to get anything done, it doesn't have the class libraries to get much done.

I am not saying you shouldn't use PHP. This is a versatile language that can be made to describe some advanced language constructs.

It is widely regarded as a slow language that scales well. Not an oxymoron when you consider performance a mixture of response time and throughput.

One thing to get used to with PHP is typing. Everything you want to do will take more characters than java, c# and especially ruby. Every method is a minimum of 19, every property reference roles in at 8 and I can assure you, we programmers do that a lot.

I spend my days developing an class model to support my web project. Some classes support the business functions I need and others just wrap the plethora of php function calls that perform the low level work I need.

Architecturally PHP offers some interesting problems. It relies a great deal of the tuning of the environment that it runs in but from a code design perspective you have to look at the transaction path as a primary and inevitable cost. In java you might start with a simple transaction path through your product layers with the realization that you can cache strategic parts as you advance your performance footprint.

In PHP there is no "cross transaction" static. So every PHP file is parsed and executed for every request. Now PHP does this pretty fast but the more you add into the transaction stream the slower things will go.

Performance is approached at the environment and code optimization level. You tune apache and add in PHP JITs to make the code run faster but you can't do much to dynamically improve transaction path across requests.

The local user group, OINKPUG, is an excellent resource full of great PHP programmers always ready to help.

All in all, I am enjoying PHP and look forward to continuing to twist to my will.