1--TEST-- 2foreach over hooked properties 3--FILE-- 4<?php 5 6#[AllowDynamicProperties] 7class ByRef { 8 public $plain = 'plain'; 9 private $_virtualByRef = 'virtualByRef'; 10 public $virtualByRef { 11 &get { 12 echo __METHOD__, "\n"; 13 return $this->_virtualByRef; 14 } 15 set { 16 echo __METHOD__, "\n"; 17 $this->_virtualByRef = $value; 18 } 19 } 20 public $virtualSetOnly { 21 set { 22 echo __METHOD__, "\n"; 23 } 24 } 25 public function __construct() { 26 $this->undef = 'dynamic'; 27 $this->dynamic = 'dynamic'; 28 unset($this->undef); 29 } 30} 31 32#[AllowDynamicProperties] 33class ByVal extends ByRef { 34 private $_virtualByVal = 'virtualByVal'; 35 public $virtualByVal { 36 get { 37 echo __METHOD__, "\n"; 38 return $this->_virtualByVal; 39 } 40 set { 41 echo __METHOD__, "\n"; 42 $this->_virtualByVal = $value; 43 } 44 } 45 public $backed = 'backed' { 46 get { 47 echo __METHOD__, "\n"; 48 return $this->backed; 49 } 50 set { 51 echo __METHOD__, "\n"; 52 $this->backed = $value; 53 } 54 } 55 public string $backedUninitialized { 56 get { 57 echo __METHOD__, "\n"; 58 $this->backedUninitialized ??= 'backedUninitialized'; 59 return $this->backedUninitialized; 60 } 61 set { 62 echo __METHOD__, "\n"; 63 $this->backedUninitialized = $value; 64 } 65 } 66} 67 68function testByRef($object) { 69 foreach ($object as $prop => &$value) { 70 echo "$prop => $value\n"; 71 $value = strtoupper($value); 72 } 73 unset($value); 74 var_dump($object); 75} 76 77function testByVal($object) { 78 foreach ($object as $prop => $value) { 79 echo "$prop => $value\n"; 80 $object->{$prop} = strtoupper($value); 81 } 82 var_dump($object); 83} 84 85testByVal(new ByVal); 86testByVal(new ByRef); 87testByRef(new ByRef); 88 89class A { 90 private $changed { get => 'A'; } 91 protected $promoted { get => 'A'; } 92 protected $protected { get => 'A'; } 93 private $shadowed = 'A'; 94 95 public function test() { 96 foreach ($this as $k => $v) { 97 var_dump($k, $v); 98 } 99 } 100} 101 102#[AllowDynamicProperties] 103class B extends A { 104 public $changed { get => 'B'; } 105 public $promoted { get => 'B'; } 106} 107 108$b = new B; 109$b->shadowed = 'Global'; 110$b->test(); 111 112?> 113--EXPECTF-- 114plain => plain 115ByRef::$virtualByRef::get 116virtualByRef => virtualByRef 117ByRef::$virtualByRef::set 118ByVal::$virtualByVal::get 119virtualByVal => virtualByVal 120ByVal::$virtualByVal::set 121ByVal::$backed::get 122backed => backed 123ByVal::$backed::set 124ByVal::$backedUninitialized::get 125backedUninitialized => backedUninitialized 126ByVal::$backedUninitialized::set 127dynamic => dynamic 128object(ByVal)#%d (6) { 129 ["plain"]=> 130 string(5) "PLAIN" 131 ["_virtualByRef":"ByRef":private]=> 132 string(12) "VIRTUALBYREF" 133 ["_virtualByVal":"ByVal":private]=> 134 string(12) "VIRTUALBYVAL" 135 ["backed"]=> 136 string(6) "BACKED" 137 ["backedUninitialized"]=> 138 string(19) "BACKEDUNINITIALIZED" 139 ["dynamic"]=> 140 string(7) "DYNAMIC" 141} 142plain => plain 143ByRef::$virtualByRef::get 144virtualByRef => virtualByRef 145ByRef::$virtualByRef::set 146dynamic => dynamic 147object(ByRef)#%d (3) { 148 ["plain"]=> 149 string(5) "PLAIN" 150 ["_virtualByRef":"ByRef":private]=> 151 string(12) "VIRTUALBYREF" 152 ["dynamic"]=> 153 string(7) "DYNAMIC" 154} 155plain => plain 156ByRef::$virtualByRef::get 157virtualByRef => virtualByRef 158dynamic => dynamic 159object(ByRef)#%d (3) { 160 ["plain"]=> 161 string(5) "PLAIN" 162 ["_virtualByRef":"ByRef":private]=> 163 string(12) "VIRTUALBYREF" 164 ["dynamic"]=> 165 string(7) "DYNAMIC" 166} 167string(7) "changed" 168string(1) "A" 169string(8) "promoted" 170string(1) "B" 171string(9) "protected" 172string(1) "A" 173string(8) "shadowed" 174string(1) "A" 175