vasayxtx
vasayxtx

Reputation: 31

__call, __callStatic and calling scope in PHP

I recently read about calling scope and scope resolution operator (::) in PHP. There are two variations: instance calling and statical calling. Consider the folowing listeng:

<?php

class A {
    public function __call($method, $parameters) {
        echo "I'm the __call() magic method".PHP_EOL;
    }

    public static function __callStatic($method, $parameters) {
        echo "I'm the __callStatic() magic method".PHP_EOL;
    }
}

class B extends A {
    public function bar() {
        A::foo();
    }
}

class C {
    public function bar() {
        A::foo();
    }
}

A::foo();
(new A)->foo();

B::bar();
(new B)->bar();

C::bar();
(new C)->bar();

The result of execution (PHP 5.4.9-4ubuntu2.2) is:

I'm the __callStatic() magic method
I'm the __call() magic method
I'm the __callStatic() magic method
I'm the __call() magic method
I'm the __callStatic() magic method
I'm the __callStatic() magic method

I don't understand why for (new C)->bar(); execute __callStatic() of A? Instance calling should made in the context of bar() method, isn't it? Is it feature of PHP?

Addition1:

Moreover, if I don't use magic methods and do explicitly call, everything works as expected:

<?php

class A {
    public function foo() {
        echo "I'm the foo() method of A class".PHP_EOL;
        echo 'Current class of $this is '.get_class($this).PHP_EOL;
        echo 'Called class is '.get_called_class().PHP_EOL;
    }
}

class B {
    public function bar() {
        A::foo();
    }
}

(new B)->bar();

Result for this:

I'm the foo() method of A class
Current class of $this is B
Called class is B

Upvotes: 3

Views: 3666

Answers (2)

newfurniturey
newfurniturey

Reputation: 38416

In the bar() method in C, you have A::foo();:

public function bar() {
    A::foo();
}

As this method is neither creating an instance of A, nor does C extend A, the :: operator is being treated as a static-operator attempting to call a static method A::foo(). Because foo() isn't defined on A, it's falling-back to the __callStatic() method.

If you want it to call the non-static method without extending A, you'll have to create an instance of A:

class C {
    public function bar() {
        $aInstance = new A();
        $aInstance->foo();
    }
}

Upvotes: 3

Mchl
Mchl

Reputation: 62369

This is because in that case we have no instance of A class. Notice that

 class B extends A

So new B gives us access to nonstatic version of A->foo.

Class C does not extend A so only static methods of A are available.

Upvotes: 0

Related Questions