Late Static Binding – Changes to parent

If you have been following the PHP internals list for the last few weeks you probably have seen a discussion concerning the current behaviour of late static binding (lsb) and how it seems to be unnecessarily limited when it comes to inheritance. I first posted about the limitations of the current lsb implementation as it relates to inheritance in Late Static Binding…Sorta. It has since been revived in this thread on the internals mailing list: RE: [PHP-DEV] late static binding php6.

I won’t rehash all of the arguments as you can quite easily find out my full thoughts by previous posts and on that mailing list thread. To put it simply I feel that somehow there needs to be a way to call methods in a parent class without losing the ability to reference back to the original called static.

 

This (or anything like it) is currently impossible in the current lsb implementation. I spent a bit of my extended weekend preparing three different patches to work around this problem. I just now sent them to the internals mailing list so they can be discussed. You can view this email and get a summary of the patches by viewing my recent php-dev posting.

All of the above patches are against 5.3. I was having some strange problems with the test suite in php6 so I moved onto php5.3 so I could make sure things weren’t breaking on me :P. If anyone reading this feels as strongly as I do that there should be a way to do this I hope to encourage you to make your thoughts known on PHP-Dev.

5 thoughts on “Late Static Binding – Changes to parent”

  1. Here is some ugly workaround in PHP.

    class O
    {
    final protected static function parent( $foo )
    {
    // getting method info
    $c = new ReflectionClass( get_called_class() );
    $m = new ReflectionMethod( $c->getParentClass()->getName(), $foo );

    // getting method location
    $start = $m->getStartLine();
    $end = $m->getEndLine();

    // gettig a code – it will fail for oneliner 😛
    $code = trim( implode( “n”, array_slice( file( $m->getFileName() ), $start, $end – $start ) ) );

    // checking if there is block begin at the beggining
    if ( $code[0] != ‘{‘ )
    $code = ‘{‘ . $code;

    // managing args
    $func_get_args = func_get_args();
    unset( $func_get_args[0] );

    $func_get_args = array_values( $func_get_args );

    foreach( $m->getParameters() as $key => $val )
    {
    if ( isset( $func_get_args[$key] ) )
    ${$val->getName()} = $func_get_args[$key];
    }

    // running code
    eval( $code );
    }
    }

    class A extends O
    {
    static public $x = ‘aaa’;

    public static function test( $a = ‘aa’, $x = ‘sas’)
    {
    echo get_called_class(); // works as supposed! writes B for B :: test();

    echo “n

    n”;
    var_dump( func_get_args() ); // wrong.. first argument is method name!
    echo “n

    n”;
    var_dump( $func_get_args ); // correct!

    echo static :: $x; // ok

    // echo self :: $x; // not ok; (wants O :: $x)

    echo A :: $x; // ok
    }
    }

    class B extends A
    {
    static public $x = ‘bbb’;

    public static function test()
    {
    // code of test() ran as parent(); but sees the correct class name
    // executed almost like parent :: test( ‘a’, new O() ); but in B-class context
    static :: parent( ‘test’, ‘a’, new O() );
    }
    }

    B::test(); //outputs B

Leave a Reply

Your email address will not be published. Required fields are marked *