1

Running PHP 5.4, so I wasn't expecting this, but I'm encountering the following error:

Parse error: syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)

Assume you have a variable of stdClass setup as follows:

$this->variable = new stdClass();

$this->variable->other = array('class' => 'helloworld');

Now, assume you want to access a static method of class helloworld:

// Standard call
$x = helloworld::my_static_method();

// Call with variable class name
$x = $this->variable->other['class']::my_static_method();

When calling the above using the variable class name, I receive the parsing error. What's odd, is that if I do the following, no error is presented:

$class = $this->variable->other['class'];

$x = $class::my_static_method();

To me this seems very odd, can anyone think of a reason why the class name isn't resolving correctly when using the first example versus the second?

hakre
  • 193,403
  • 52
  • 435
  • 836
William Orazi
  • 1,694
  • 6
  • 23
  • 36

2 Answers2

2

can anyone think of a reason why the class name isn't resolving correctly when using the first example versus the second?

The PHP parser does not support such a syntax, and that's merely all. This is because the parser has grown historically. I can't give more reason than that.

It will be that with PHP 7 you can see some changes on these syntax details working more into your expected direction Uniform Variable Syntax:

($variable->other['class'])::my_static_method();

But until then, you can go around that with the help of call_user_func:

call_user_func([$variable->other['class'], 'my_static_method']);
call_user_func($variable->other['class'] . '::my_static_method');

Or as you wrote your own, by creating a variable:

$class = $variable->other['class'];
$class::my_static_method();

Or even a variable that looks like something different:

${(int)!${0}=$variable->other['class']}::my_static_method();

Related Material:

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836
  • Thanks for the explanation. Good to see they'll be supporting some more exotic syntax use for PHP 7. – William Orazi Mar 20 '15 at 15:11
  • I won't say the PHP 7 syntax is exotic, even the other way round: it's more consistent then. And I'm glad this has been finally tackled with :) – hakre Mar 20 '15 at 15:13
1

This doesn't work ($this->variable->other['class']::my_static_method()) as it's essentially using a string as the class name directly. It works when you assign it to a variable first, as it's then being evaluated out as the class name instead.

You can also look into using ReflectionMethod invocation in order to call the method, in which case you wouldn't have to store the class name in a variable before using it. Here's the docs on that: http://php.net/manual/en/class.reflectionmethod.php and on the invoke method (you pass in NULL to indicate a static method) http://php.net/manual/en/reflectionmethod.invoke.php

Here are a couple examples of ways to invoke your function:

class helloworld{
    public static function my_static_method($i = 0){
        echo "Here: ".$i;
    }
}

class Foo{
    private $variable;

    public function __construct(){
        //Create a new class
        $this->variable = new stdClass();

        //Create a new property of the class, storing an array
        $this->variable->other = array('class' => 'helloworld');

        //Call function statically
        $x = helloworld::my_static_method(1); //Outputs: "Here: 1"

        //Store class name in a variable before use
        $class = $this->variable->other['class'];
        $y = $class::my_static_method(2); //Outputs: "Here: 2"

        //Using a ReflectionMethod, you can call the function this way, too
        $z = new ReflectionMethod($this->variable->other['class'], 'my_static_method');
        $z->invoke(null, 3); //Outputs: "Here: 3"
    }
}

//Instantiate new Foo class
new Foo();
M Sost
  • 1,133
  • 7
  • 15
  • Interesting - I guess I'm just curious why (in your example) `$class` resolves correctly, but `$this->variable->other['class']` does not? In my mind, both variables resolve to the string, `helloworld`. In your comment, "...it's essentially using a string as the class name directly. It works when you assign it to a variable first, as it's then being evaluated out as the class name instead." Why aren't they both evaluated out to the class name? – William Orazi Mar 19 '15 at 20:38
  • It's also interesting, because calling `new $this->variable->other['class']()` works...wouldn't that fall under the same issue? – William Orazi Mar 19 '15 at 20:43
  • 1
    So, interestingly enough, when you're using `$this->variable->other['class']` it's being evaluated as a string. Strings don't have a `::` method (i.e. the parser doesn't recognize static method invocation of the string), which is why you need to use a variable (in which case the parser is able to evaluate the variable contents as a class, and the static method invocation works). With your second comment, since you're no longer using static method invocation, `$this->variable->other['class']()` works as expected. – M Sost Mar 19 '15 at 20:51
  • You can see some info on some of the dynamic language features here (although it's namespaced-base docs): http://php.net/manual/en/language.namespaces.dynamic.php and also the class reference docs here: http://php.net/manual/en/language.oop5.basic.php – M Sost Mar 19 '15 at 20:52