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?

2 Answers 2

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:

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the explanation. Good to see they'll be supporting some more exotic syntax use for PHP 7.
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 :)
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();

4 Comments

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?
It's also interesting, because calling new $this->variable->other['class']() works...wouldn't that fall under the same issue?
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.
You can see some info on some of the dynamic language features here (although it's namespaced-base docs): php.net/manual/en/language.namespaces.dynamic.php and also the class reference docs here: php.net/manual/en/language.oop5.basic.php

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.