fork download
  1. <?php
  2. header('Content-Type: text/plain');
  3. class HasFriends
  4. {
  5. protected $__friends = array('HasFriends');
  6.  
  7. public function __get($key)
  8. {
  9. $res=NULL;
  10. $trace = debug_backtrace();
  11. $frame=0;
  12. while($frame < count($trace) && $trace[$frame]['class']==__CLASS__) $frame++;
  13. if(isset($trace[$frame]['class']) && in_array($trace[$frame]['class'], $this->__friends)) {
  14. //return $this->$key;
  15. $rc=new ReflectionClass($this);
  16. $prop=$rc->getProperty($key);
  17. $prop->setAccessible(true);
  18. $res=$prop->getValue($this);
  19. return $res;
  20. }
  21.  
  22. // normal __get() code here
  23. throw new Exception('Cannot access private property ' . get_class($this) . '::$' . $key . "\r\n", E_USER_ERROR);
  24. }
  25.  
  26. public function __set($key, $value)
  27. {
  28. $res=NULL;
  29. $trace = debug_backtrace();
  30. $frame=0;
  31. while($frame < count($trace) && $trace[$frame]['class']==__CLASS__) $frame++;
  32. if(isset($trace[$frame]['class']) && in_array($trace[$frame]['class'], $this->__friends)) {
  33. //return $this->$key = $value;
  34. $rc=new ReflectionClass($this);
  35. $prop=$rc->getProperty($key);
  36. $prop->setAccessible(true);
  37. $res=$prop->setValue($this, $value);
  38. return $res;
  39. }
  40.  
  41. // normal __set() code here
  42. throw new Exception('Cannot access private property ' . get_class($this) . '::$' . $key . "\r\n", E_USER_ERROR);
  43. }
  44.  
  45. public function __call($name, $arguments)
  46. {
  47. $res=NULL;
  48. $trace = debug_backtrace();
  49. $frame=0;
  50. while($frame < count($trace) && $trace[$frame]['class']==__CLASS__) $frame++;
  51. if(isset($trace[$frame]['class']) && in_array($trace[$frame]['class'], $this->__friends)) {
  52. //return call_user_func_array(array($this, $name), $this->arguments);
  53. $rc=new ReflectionClass($this);
  54. $meth=$rc->getMethod($name);
  55. $meth->setAccessible(true);
  56. $res=$meth->invokeArgs($this, $arguments);
  57. return $res;
  58. }
  59. // normal __call() code here
  60. throw new Exception('Cannot call private method ' . get_class($this) . '::' . $name . '()' . "\r\n", E_USER_ERROR);
  61. }
  62.  
  63. public static function __callStatic($name, $arguments)
  64. {
  65. $trace = debug_backtrace();
  66. $frame=0;
  67. while($frame < count($trace) && $trace[$frame]['class']==__CLASS__) $frame++;
  68. if(isset($trace[$frame]['class']) && in_array($trace[$frame]['class'], $this->__friends)) {
  69. //return call_user_func_array(array(get_class($this), $name), $this->arguments);
  70. $rc=new ReflectionClass(get_class($this));
  71. $meth=$rc->getMethod($name);
  72. $meth->setAccessible(true);
  73. $res=$meth->invokeArgs(NULL, $arguments);
  74. return $res;
  75. }
  76. // normal __callStatic() code here
  77. throw new Exception('Cannot call static private method ' . get_class($this) . '::' . $name . '()' . "\r\n", E_USER_ERROR);
  78. }
  79. };
  80. class A extends HasFriends
  81. {
  82.  
  83. public $a = 1;
  84. protected $b = 2;
  85. private $c = 3;
  86. protected $__friends = array('B');
  87. private function d() { return 4; }
  88. };
  89. class B
  90. {
  91. public $d = 4;
  92. protected $e = 5;
  93. private $f = 6;
  94. public $a = NULL;
  95. public function getC()
  96. {
  97. return $this->a->c;
  98. }
  99. public function g() { return $this->a->d(); }
  100. };
  101. $a = new A();
  102. $b = new B();
  103. $b->a = &$a;
  104. echo 'var_dump($a)='."\r\n";
  105. echo 'var_dump($b)='."\r\n";
  106. try
  107. {
  108. echo 'Trying to access A::c'."\r\n";
  109. var_dump($a->c);
  110. }
  111. catch(Exception $e)
  112. {
  113. echo $e->getMessage();
  114. }
  115. try
  116. {
  117. echo 'Trying to access B::a::c'."\r\n";
  118. var_dump($b->a->c);
  119. }
  120. catch(Exception $e)
  121. {
  122. echo $e->getMessage();
  123. }
  124. echo 'Accessing B::getC(), which returns B::a::c'."\r\n";
  125. var_dump($b->getC());
  126. try
  127. {
  128. echo 'Trying to access A::d()'."\r\n";
  129. var_dump($a->d());
  130. }
  131. catch(Exception $e)
  132. {
  133. echo $e->getMessage();
  134. }
  135. echo 'Accessing B::g(), which returns B::a::d()'."\r\n";
  136. var_dump($b->g());
  137.  
Success #stdin #stdout 0.02s 23696KB
stdin
Standard input is empty
stdout
var_dump($a)=
object(A)#1 (4) {
  ["a"]=>
  int(1)
  ["b":protected]=>
  int(2)
  ["c":"A":private]=>
  int(3)
  ["__friends":protected]=>
  array(1) {
    [0]=>
    string(1) "B"
  }
}
var_dump($b)=
object(B)#2 (4) {
  ["d"]=>
  int(4)
  ["e":protected]=>
  int(5)
  ["f":"B":private]=>
  int(6)
  ["a"]=>
  &object(A)#1 (4) {
    ["a"]=>
    int(1)
    ["b":protected]=>
    int(2)
    ["c":"A":private]=>
    int(3)
    ["__friends":protected]=>
    array(1) {
      [0]=>
      string(1) "B"
    }
  }
}
Trying to access A::c
Cannot access private property A::$c
Trying to access B::a::c
Cannot access private property A::$c
Accessing B::getC(), which returns B::a::c
int(3)
Trying to access A::d()
Cannot call private method A::d()
Accessing B::g(), which returns B::a::d()
int(4)