Bug #78859 [NEW]: Weird behavior with uninitialized typed properties and __set/__get

From: Date: Fri, 22 Nov 2019 21:05:58 +0000
Subject: Bug #78859 [NEW]: Weird behavior with uninitialized typed properties and __set/__get
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-223864@lists.php.net to get a copy of this message
From: krmgns at gmail dot com Operating system: Ubuntu 18.04 PHP version: 7.4.0RC6 Package: *General Issues Bug Type: Bug Bug description:Weird behavior with uninitialized typed properties and __set/__get Description: ------------ Seems calling a constructor is triggering __set magic for uninitialized typed properties. So it does not matter the property is public or private/protected. I suppose the problem is __set/__get called before __construct when a type is given to a property. Also I if remove __get then I get object(acme\Options)#1 (1) { ["stack"]=> array(1) { ["stack"]=> array(1) { ["one"]=> int(1) } } }. Test script: --------------- final class Options { // This is OK but why redundant initialization? // public array $stack = []; public array $stack; public function __construct(array $stack) { $this->stack = $stack; } public function __set(string $name, $value) { // if (empty($this->stack)) { // // This line below yields: object(acme\Options)#1 (0) { ["stack"]=> uninitialized(array) }. // // return; // // This line below yields: object(acme\Options)#1 (1) { ["stack"]=> array(1) { ["stack"]=> array(1) { ["one"]=> int(1) } } }. // // $this->stack = []; // } // This is solving problem but the purpose is not that also corrupting $stack structure inserting a new sub-array. // object(acme\Options)#1 (1) { ["stack"]=> array(2) { ["one"]=> int(1) ["stack"]=> array(1) { ["one"]=> int(1) } } } // $this->stack = $value; // This is indicating that __set called before (before __construct). // throw new \Exception(); // This is problematic part. $this->stack[$name] = $value; } public function __get(string $name) { // This is indicating that __get called before (before __construct). // throw new \Exception(); return $this->stack[$name] ?? null; } } var_dump(new Options(['one' => 1])); Expected result: ---------------- object(acme\Options)#1 (1) { ["stack"]=> array(1) { ["one"]=> int(1) } } Actual result: -------------- PHP Notice: Indirect modification of overloaded property acme\Options::$stack has no effect in /var/www/a.php on line 19 PHP Fatal error: Uncaught TypeError: Typed property acme\Options::$stack must be array, null used in /var/www/a.php:19 Stack trace: #0 /var/www/a.php(16): acme\Options->__set() #1 /var/www/a.php(26): acme\Options->__construct() #2 {main} thrown in /var/www/a.php on line 19 -- Edit bug report at https://bugs.php.net/bug.php?id=78859&edit=1 -- Fix committed: https://bugs.php.net/fix.php?id=78859&r=fixed Fixed in release: https://bugs.php.net/fix.php?id=78859&r=alreadyfixed Need backtrace: https://bugs.php.net/fix.php?id=78859&r=needtrace Need Reproduce Script: https://bugs.php.net/fix.php?id=78859&r=needscript Try newer version: https://bugs.php.net/fix.php?id=78859&r=oldversion Not developer issue: https://bugs.php.net/fix.php?id=78859&r=support Expected behavior: https://bugs.php.net/fix.php?id=78859&r=notwrong Not enough info: https://bugs.php.net/fix.php?id=78859&r=notenoughinfo Submitted twice: https://bugs.php.net/fix.php?id=78859&r=submittedtwice register_globals: https://bugs.php.net/fix.php?id=78859&r=globals PHP version support discontinued: https://bugs.php.net/fix.php?id=78859&r=phptooold Daylight Savings: https://bugs.php.net/fix.php?id=78859&r=dst IIS Stability: https://bugs.php.net/fix.php?id=78859&r=isapi Install GNU Sed: https://bugs.php.net/fix.php?id=78859&r=gnused Floating point limitations: https://bugs.php.net/fix.php?id=78859&r=float No Zend Extensions: https://bugs.php.net/fix.php?id=78859&r=nozend MySQL Configuration Error: https://bugs.php.net/fix.php?id=78859&r=mysqlcfg

« previous php.bugs (#223864) next »