[php-src] Issue #9906: Add argument $callingScope to magic method get/set/isset/unset

From: Date: Tue, 08 Nov 2022 15:41:09 +0000
Subject: [php-src] Issue #9906: Add argument $callingScope to magic method get/set/isset/unset
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-242768@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/9906 Author: nicolas-grekas ### Description I worked quite a lot with magic methods recently and I figured out that they should accept a extra argument: the calling scope, as a class name (or null when not called from a class). This would help to properly implement visibility-related logic. Right now, we have to call debug_backtrace() to write such logics, but everybody forgets about it and more annoyingly this doesn't work well with inheritance (calling parent::__get() changes the outcome of debug_backtrace() inside this parent::__get method.) Adding the calling scope would make this concern more evident and would solve the issue with inheritance. It would also fix the edge case of calling a magic method via ReflectionProperty::get/setValue, where looking up at debug_backtrace() needs special care to extract the calling scope. Before: ```php class Foo extends Bar { public function __get($name): mixed { $frame = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, 3)[1]; $callingScope = $frame['class'] ?? null; if (\ReflectionProperty::class === $callingScope) { $callingScope = $frame['object']->class; } // Now we can implement visibility-related logic for accessing $name // Let's say we want to call parent::__get() and it uses the same logic to extract the calling // scope, it's now broken because instead of getting frame [1], it should use frame [2], // but knowing this requires more non trivial logic. } } ``` After: ```php class Foo extends Bar { public function __get($name, ?string $callingScope = null): mixed { // $callingScope is populated with the value computed before // And calling parent::__get($name, $callingScope) is done easily without resorting to any specific logic } } ```

« previous php.bugs (#242768) next »