Bug #81436 [Opn->Fbk]: Unexpected behavior when utilizing __call and __callStatic from different scope
Edit report at https://bugs.php.net/bug.php?id=81436&edit=1
ID: 81436
Updated by: requinix@php.net
Reported by: dev98 at outlook dot de
Summary: Unexpected behavior when utilizing __call and
__callStatic from different scope
-Status: Open
+Status: Feedback
Type: Bug
Package: Scripting Engine problem
Operating System: Windows x64, Manjaro Linux x64
PHP Version: Irrelevant
Block user comment: N
Private report: N
New Comment:
> and you might argue that "that's not a static call operator, its a scope resolution
> operator."
But that's exactly the answer: the double colon is to resolve how a method should be called,
not to do a static call. "A::BLA" will resolve to an instance call if you're in the
scope of an instance of A or a static call if not.
A::doMagicCall_from_staticContext:
- has no instance of A so A::BLA() is a static method call
- has no instance of B so B::BLA() is a static method call
A->doMagicCall_from_objectContext:
- inside an instance of A so A::BLA() is an instanced method call
- has no instance of B so B::BLA() is a static method call
Look at the typical child constructor pattern:
public function __construct() {
parent::__construct();
$this->foo = "bar";
}
parent::__construct is not called statically, and neither "parent" nor
"__construct" have any kind of special meaning that would secretly change ::'s scope
resolution process to work differently than it normally would.
__call and __callStatic only enter the picture at the very last minute when PHP is actually trying
to call the method and when it finds out that "BLA" does not exist. By that point it has
already decided whether "BLA" should be an instanced call or not, and it will select
__call or __callStatic appropriately.
Previous Comments:
------------------------------------------------------------------------
[2021-09-14 11:20:43] dev98 at outlook dot de
Description:
------------
When we utilize the __callStatic function with an appropriate static call on the same class the
magic function is defined while being in an object scope, for some reason, the __call method will
get invoked. This seems very unintuitive as the php doc states:
"__call() is triggered when invoking inaccessible methods in an object context."
We also tested it in 7.3.10-nts-Win32-VC15-x64, 5.6.40-nts-Win32-VC11-x86 and 8.0.10-nts-Linux-x64.
Results are consistent.
Testscript is crunched down in lines. For a nice formatting and code comments please visit https://stackoverflow.com/questions/69161169/unexpected-behavior-when-utilizing-call-and-callstatic-from-different-scopes
I have read the threads with bug id 51176 & 77344
and you might argue that "that's not a static call operator, its a scope resolution
operator." But since 2008 calling non static members statically causes error messages. Further
more when you replace the calls on the non existing members with an forward_static_call, which
literally is documented with "Call a static method", it results in the same behavior.
Reproducible with replacing the calls
A::BLA(), B::BLA() with forward_static_call(array("A", "BLA")),
forward_static_call(array("B", "BLA"));
I understand the behavior daniel described in bug.php?id=51176 [2013-08-17 13:59 UTC] daniel dot
ruthardt at zoesolutions dot eu, but either the __call magic function catches the wrong call or
forward_static_call should be rather called forward_scope_resolution_operator_call. Ive got the
feeling here that there is not a consent about how the :: operator should actually work.
Thanks in advance and lovely greetings from Germany
Test script:
---------------
class B {
public function __call($name, $arguments) {print(" __CALL on B\r\n");}
public static function __callStatic($name, $arguments) {print(" __STATICCALL on
B\r\n");}
}
class A {
public function __call($name, $arguments) {print(" __CALL on A\r\n");}
public static function __callStatic($name, $arguments) {print(" __STATICCALL on
A\r\n");}
public static function doMagicCall_from_staticContext() {
A::BLA(); // expect A::__callStatic, works
B::BLA(); // expect B::__callStatic, works
}
public function doMagicCall_from_objectContext() {
A::BLA(); // expect A::__callStatic, got $this->__call(), prints "__CALL on A"
B::BLA(); // expect B::__callStatic, works
}
}
$a = new A();
print("1. Call from static context:\r\n");
A::doMagicCall_from_staticContext();
print("\r\n2. Call from object context:\r\n");
$a->doMagicCall_from_objectContext(); // provokes the behavior
Expected result:
----------------
1. Call from static context:
__STATICCALL on A
__STATICCALL on B
2. Call from object context:
__STATICCALL on A
__STATICCALL on B
Actual result:
--------------
1. Call from static context:
__STATICCALL on A
__STATICCALL on B
2. Call from object context:
__CALL on A
__STATICCALL on B
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=81436&edit=1
Thread (6 messages)