3

I found some strange PHP behaviour, I'm interested if someone could explain me why some parts of this code works, while others don't.

PHP can create new classes dynamically when class names are stored in variables. And it works fine since I'm using a modern version of PHP (5.5.28). But I found some strange behaviour that I don't really understand.

The problem occurs when the class name is stored in a property of some object. In this case, static functions cannot be called on the dynamic class: $this->dynClass::SomeFunction() fails and ($this->dynClass)::SomeFunction() fails as well. However $instance = new $this->dynClass works. So if I need to call a static method on $this->dynClass, I have to create a local variable storing the same string: $tmp = $this->dynClass. And then, I can call $tmp::SomeFunction()

I really don't understand this. Could this be a bug? Please someone explain me.

Here's my example code:

<?php
    class MyClass {
        static function SomeFunction($name){
            echo "Hello $name\n";
        }
    }

    MyClass::SomeFunction("World"); //Works fine as it should, prints Hello World

    $firstInstance = new MyClass;
    $firstInstance::SomeFunction("First"); //prints hello first, no problem

    //here comes the interesting part

    $dynClass = "MyClass";

    $dynClass::SomeFunction("Dynamic"); //Yeah, it works as well

    $secondInstance = new $dynClass;
    $secondInstance::SomeFunction("Second"); //Hello Second. Fine.

    //And here comes the part that I don't understand

    class OtherClass {
        private $dynClass = "MyClass";

        public function test(){

            $thirdInstance = new $this->dynClass; //WORKS!
            $thirdInstance::SomeFunction('Third'); //Hello Third

            //BUT

            $this->dynClass::SomeFunction("This"); //PHP Parse error:  syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)

            //OK, but then this one should work:

            ($this->dynClass)::SomeFunction("This"); //same error. WHY??

            //The only solution is creating a local variable:
            $tmp = $this->dynClass;
            $tmp::SomeFunction("Local"); //Hello Local

        }
    }

    $otherInstance = new OtherClass;
    $otherInstance->test();

?>
balping
  • 7,518
  • 3
  • 21
  • 35
  • 2
    I dont understand php internals, so i cant tell you exactly why, but it looks like it is fixed in php 7. Live example using current php7 beta: http://codepad.viper-7.com/CfJtD3 the rfc for the fix: https://wiki.php.net/rfc/uniform_variable_syntax – Steve Aug 20 '15 at 14:08

1 Answers1

1

Before the Uniform Variable Syntax, php's variable parsing was basically a big lump of corner cases.

In particular, certain operations, like ::, where not supported on (...) expressions.

The two errors you encountered are examples of this loosely defined and inconsistent variable parser.

T0xicCode
  • 4,583
  • 2
  • 37
  • 50