Bug #81436 [Com]: Unexpected behavior when utilizing __call and __callStatic from different scope

From: Date: Tue, 14 Sep 2021 13:31:27 +0000
Subject: Bug #81436 [Com]: Unexpected behavior when utilizing __call and __callStatic from different scope
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-236593@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=81436&edit=1 ID: 81436 Comment by: nerdbeere2k at gmail dot com Reported by: dev98 at outlook dot de Summary: Unexpected behavior when utilizing __call and __callStatic from different scope 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: I fail to understand why this works the way it does as well. If you replace the A::BLA code with: forward_static_call(array("A", "BLA")) I feel it should definitely call the static method BLA on A and not anything else. Or asked differently: How would one call A::BLA from an object context? Is this impossible? Previous Comments: ------------------------------------------------------------------------ [2021-09-14 13:16:43] requinix@php.net Of course it's only once I hit the Submit button do I see an edit to make: > the double colon is to resolve how a method should be called Makes more sense to say it resolves *where* a method should be called. ------------------------------------------------------------------------ [2021-09-14 13:13:20] requinix@php.net > 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. ------------------------------------------------------------------------ [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

« previous php.bugs (#236593) next »