I have come up with three different patches that allow us to work around
the issue of parent:: being considered an 'explicit class reference' and
thus disallowing static:: to effectively used.
The patches are against 5.3. I also have patches against HEAD but I was
having problems getting run-tests.php to run against that code base (it
would hang on the first test no matter which set of tests I ws running.)
All three patches have different levels of intrusiveness to the engine
and all three patches have been tested against (and pass) the existing
lsb tests in Zend/tests/lsb_*.phpt
1.) lsb.parent-forwarding.patch
This patch modifies the behavior of only parent:: to not change
EG(called_class) to the parent of the current scope. With this change.
<?php
class A {
public static function test() {
echo get_called_class()."\n";
}
}
class B extends A {
public static function test() {
parent::test();
}
}
A::test();
B::test();
?>
will output:
A
B
It should be noticed that with this patch parent:: will always resolve
to the parent of the current scope, it will just not make any changes to
the called_scope (effectively)
2.) lsb.new-keyword.patch
This patch effectively does the same thing as the parent forwarding
patch, but does it by introducing a new keyword. I had no idea what to
call this keyword so for the time being I am using '__parentf'. If this
is a direction people want to go this can of course be changed with a
relatively simple search & replace in the patch file.
The code above would need to be changed to:
<?php
class A {
public static function test() {
echo get_called_class()."\n";
}
}
class B extends A {
public static function test() {
__parentf::test();
}
}
A::test();
B::test();
?>
This patch carries the same costs as the parent forwarding patch with
the additional costs of having to check for a new keyword when declaring
classes/namespaces/interfaces and calling static methods. Perhaps
someone knows a cheaper way to do this?
3.) lsb.forward_static_call.patch
This patch implements my desired functionality by using two new
functions: forward_static_call() and forward_static_call_array(). These
functions ares similar to the call_user_func*() functions however the
first parameter is not a callback but a string specifying the desired
static method that exists in the current scope's parent class. The
function will error out with messages similar to parent:: if called from
outside of a class or from within a class that does not have a parent.
So with this patch the code would change to:
<?php
class A {
public static function test() {
echo get_called_class()."\n";
}
}
class B extends A {
public static function test() {
forward_static_call(__FUNCTION__);
}
}
A::test();
B::test();
?>
This patch is completely outside of the Zend engine and as such existing
lsb functionality is not affected at all.
So, with these three options on the table I think it is very clear that
what we are asking for can be done with varying levels of
'intrusiveness', so what does everyone think?
If one of these options looks worth pursuing I can put together the
tests I have written for all of them, cleanup the code, help with
documentation, etc.
- Mike Lively
http://www.digitalsandwich.com