<?php
namespace app;
define('YII_ENV_PROD', false);
class BaseObject
{
protected $enableFriendClassesInProd = false;
protected $calledClassStackLimit = 0;
protected $friendParents = false;
protected $friendDescendants = false;
protected $friendClasses = [];
public function __call($name, $args)
{
if (method_exists($this, $name) && method_exists($this, '_call')) {
if (!YII_ENV_PROD || $enableFriendClassesInProd ) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, $this->calledClassStackLimit);
$stackClasses = array_column($backtrace, 'class');
$calledClass = array_pop($stackClasses);
if (in_array($calledClass, $this->friendClasses)) {
return call_user_func_array([$this, '_call'], [$name, $args]);
} elseif ($this->friendDescendants && is_subclass_of($calledClass, static::class)) {
return call_user_func_array([$this, '_call'], [$name, $args]);
} elseif ($this->friendParents && is_subclass_of(static::class, $calledClass)) {
return call_user_func_array([$this, '_call'], [$name, $args]);
} else {
throw new \Exception('Method disallowed: ' . get_class($this) . '::' . $name);
}
}
return call_user_func_array([$this, '_call'], [$name, $args]);
} else {
throw new \Exception('Calling unknown method:' . get_class($this) . '::' . $name);
}
}
public function __get($name)
{
$getter = 'get' . $name;
if (method_exists($this, $getter)) {
return $this->$getter();
} elseif (method_exists($this, 'set' . $name)) {
throw new \Exception('Getting write-only property: ' . get_class($this) . '::' . $name);
}
throw new \Exception('Getting unknown property: ' . get_class($this) . '::' . $name);
}
public function __set($name, $value)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) {
$this->$setter($value);
} elseif (method_exists($this, 'get' . $name)) {
throw new \Exception('Setting read-only property: ' . get_class($this) . '::' . $name);
} else {
throw new \Exception('Setting unknown property: ' . get_class($this) . '::' . $name);
}
}
}
class Yii
{
public static $app;
}
class A extends BaseObject
{
protected $friendDescendants = true;
private function showName()
{
echo __CLASS__;
}
protected function _call($name, $args)
{
return call_user_func_array([$this, $name], $args);
}
}
class B extends A
{
public function myName()
{
Yii::$app->showName();
}
}
Yii::$app = new A();
$b = new B();
$b->myName();
- Output for 7.2.0 - 7.2.33, 7.3.0 - 7.3.33, 7.4.0 - 7.4.33, 8.0.0 - 8.0.30, 8.1.0 - 8.1.33, 8.2.0 - 8.2.29, 8.3.0 - 8.3.25, 8.4.1 - 8.4.12
- app\A
preferences:
150.52 ms | 407 KiB | 5 Q