call_user_func_array 和 __call 创建无限循环
call_user_func_array and __call create infinite loop
我有一个 class A
和 class B
继承自 class A
,我想 运行 在 运行 函数之前进行一些检查。
class A {
public class __call($name, $params) {
if (method_exists?($this, $name)) {
$result = call_user_func_array([$this, $name], $params);
return $result;
}
}
}
class B {
private function hello() {
echo "Hello"
}
}
我期待的是当我打电话时:
$b = new B();
$b->hello();
它会调用__call
然后执行private function hello
,但是它开始无限循环,看起来call_user_func_array
又触发了__call
。
但是如果我在 class A
中创建 hello
函数,代码就可以工作
这是预期的行为吗?
我可以做些什么来防止这种情况发生?
玩了一会儿后,看来您可以将 hello 函数设置为 protected 而不是 private。
您的代码有几个小问题。查看评论。
class A {
public function __call($name, $params) {
if (method_exists($this, "{$name}")) {
$this->before();
$result = call_user_func_array([$this, "{$name}"], $params);
$this->after();
return $result;
}
}
private function before() {
echo "before\n";
}
private function after() {
echo "after\n";
}
}
class B extends A {
protected function hello() {
echo "Hello\n";
}
}
$b = new B();
$b->hello();
当我运行它时,这是我得到的结果。
before
Hello
after
我 运行 它在 PHP 7.0.8.
简短回答:Public 父类 class 中的方法不能调用子类 class 中的私有方法。
你也可以使用特质。
trait Wrappable
{
public function __call($name, $params) {
if (method_exists($this, $name)) {
$this->before();
$result = call_user_func_array([$this, $name], $params);
$this->after();
return $result;
}
}
private function before() {
echo "before\n";
}
private function after() {
echo "after\n";
}
}
class A {
use Wrappable;
public function pub()
{
echo __METHOD__ . "\n";
}
}
class B {
use Wrappable;
protected function hello() {
echo "Hello\n";
}
protected function protHello()
{
echo __METHOD__ . "\n";
$this->privHello();
}
protected function visibilityBridge($f, $a)
{
}
private function privHello()
{
echo __METHOD__ . "\n";
}
}
$a = new A();
$a->pub();
$b = new B();
$b->privHello();
数组解构需要PHP7+
class A {
public function __call($name, $params) { //this is a function
if (method_exists($this, $name)) { // Remove ?
$result = $this->$name(...$params); //Really calls the function from the context
return $result;
}
// As a suggestion you should throw an exception here for maintainability
}
}
class B extends A { // You need 'extends A'
private function hello() {
echo "Hello"; // ;
}
}
$b = new B();
$b->hello(); // Hello
我有一个 class A
和 class B
继承自 class A
,我想 运行 在 运行 函数之前进行一些检查。
class A {
public class __call($name, $params) {
if (method_exists?($this, $name)) {
$result = call_user_func_array([$this, $name], $params);
return $result;
}
}
}
class B {
private function hello() {
echo "Hello"
}
}
我期待的是当我打电话时:
$b = new B();
$b->hello();
它会调用__call
然后执行private function hello
,但是它开始无限循环,看起来call_user_func_array
又触发了__call
。
但是如果我在 class A
hello
函数,代码就可以工作
这是预期的行为吗? 我可以做些什么来防止这种情况发生?
玩了一会儿后,看来您可以将 hello 函数设置为 protected 而不是 private。
您的代码有几个小问题。查看评论。
class A {
public function __call($name, $params) {
if (method_exists($this, "{$name}")) {
$this->before();
$result = call_user_func_array([$this, "{$name}"], $params);
$this->after();
return $result;
}
}
private function before() {
echo "before\n";
}
private function after() {
echo "after\n";
}
}
class B extends A {
protected function hello() {
echo "Hello\n";
}
}
$b = new B();
$b->hello();
当我运行它时,这是我得到的结果。
before
Hello
after
我 运行 它在 PHP 7.0.8.
简短回答:Public 父类 class 中的方法不能调用子类 class 中的私有方法。
你也可以使用特质。
trait Wrappable
{
public function __call($name, $params) {
if (method_exists($this, $name)) {
$this->before();
$result = call_user_func_array([$this, $name], $params);
$this->after();
return $result;
}
}
private function before() {
echo "before\n";
}
private function after() {
echo "after\n";
}
}
class A {
use Wrappable;
public function pub()
{
echo __METHOD__ . "\n";
}
}
class B {
use Wrappable;
protected function hello() {
echo "Hello\n";
}
protected function protHello()
{
echo __METHOD__ . "\n";
$this->privHello();
}
protected function visibilityBridge($f, $a)
{
}
private function privHello()
{
echo __METHOD__ . "\n";
}
}
$a = new A();
$a->pub();
$b = new B();
$b->privHello();
数组解构需要PHP7+
class A {
public function __call($name, $params) { //this is a function
if (method_exists($this, $name)) { // Remove ?
$result = $this->$name(...$params); //Really calls the function from the context
return $result;
}
// As a suggestion you should throw an exception here for maintainability
}
}
class B extends A { // You need 'extends A'
private function hello() {
echo "Hello"; // ;
}
}
$b = new B();
$b->hello(); // Hello