3

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
vasayxtx
  • 31
  • 1
  • 3

2 Answers2

3

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();
    }
}
newfurniturey
  • 37,556
  • 9
  • 94
  • 102
  • `::` don't always mean statical call. It depends on calling scope. For `(new B)->bar();` execute `bar()` method of `B` class and than `A::foo()` and in this case made `__callStatic()`, because it is instance calling scope. – vasayxtx Aug 28 '13 at 12:37
  • @vasayxtx Sorry, I guess it's bad wording on my part. I meant that in the context of C.bar(), it's being used as a `static` operator. Let me re-word, hopefully I can make it more clear. – newfurniturey Aug 28 '13 at 12:39
0

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.

Mchl
  • 61,444
  • 9
  • 118
  • 120
  • Ok, I get it. It wasn't enough obvious, at least for me. – vasayxtx Aug 28 '13 at 12:48
  • Don't worry. This stuff can get tricky and requires some attention so as not to overlook some minor, yet important detail. – Mchl Aug 28 '13 at 12:52
  • "Class C does not extend A so only static methods of A are available." Can I read about it in the manual? – vasayxtx Aug 28 '13 at 12:53
  • Would you see my addition1 and explain me why it works as expected. Is your saing applicable only to magic method __call()? – vasayxtx Aug 28 '13 at 13:35