我有一个非常奇怪的问题,我不知道这是否归因于call_user_func_array
。
在PHP 5.4上进行测试
当前设置
例如,我有一个AuthController
类,它扩展了一个名为Controller
的基本控制器:
class AuthController extends Controller
{
public function login() {
return Response::json(array('error' => false, 'message' => 'I\'m in AuthController@login'));
}
}
在扩展的Controller
类中,我有一个构造函数来设置,例如,数据库连接(为了测试目的,我添加了一个var_dump + exit):
class Controller
{
protected $db;
protected function __construct() {
$database = Config::env('database');
var_dump($database);
exit;
}
}
现在拨打AuthController
,我正在使用call_user_func_array
call_user_func_array(array($controller, $route['action']), $data);
现在应该发生什么:
应该发生的事情是Controller
的构造函数应该被触发,在屏幕上产生转储并退出执行。
相反:
相反,我实际上是从AuthController
的登录方法Response::json()
获得回复。
Controller
的构造函数永远不会被解雇。
我很难理解为什么它不起作用,因为PHP手册指出构造函数会在每个新对象实例上被触发,并且如果父类有一个构造函数且子类没有覆盖它,自动调用父类构造函数。
call_user_func_array
是否自动触发父类构造函数或者我是否完全误解了PHP构造函数?
答案 0 :(得分:2)
我会在黑暗中捅一下,并说你实际上是这样做的:
call_user_func_array(array('AuthController', 'login'), $data);
换句话说,您未将实例传递给call_user_func
,而您只是传递字符串'AuthController'
。这意味着您的方法将被静态调用 。如果您启用了错误报告和/或严格错误报告,您应该会看到一条警告,提醒您静态调用非静态方法。
问题是(可能)你从未真正实例化你的类,所以没有任何构造函数运行。 call_user_func
无法为您实例化它。你自己需要这样做:
call_user_func_array(array(new $controller, $route['action']), $data);
// ^^^
答案 1 :(得分:1)
作为http://php.net/manual/en/language.oop5.decon.php
上的PHP文档PHP 5允许开发人员为类声明构造函数方法。具有构造函数方法的类在每个新创建的对象上调用此方法,因此它适用于对象在使用之前可能需要的任何初始化。
注意:如果子类定义了构造函数,则不会隐式调用父构造函数。为了运行父构造函数,需要在子构造函数中调用 parent :: __ construct()。如果子进程没有定义构造函数,那么它可以像普通的类方法一样从父类继承(如果它没有被声明为私有)。
示例#1使用新的统一构造函数
<?php
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
}
// In BaseClass constructor
$obj = new BaseClass();
// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass();
// In BaseClass constructor
$obj = new OtherSubClass();
?>
希望这能解释你在子类中使用父类构造函数。
你也可以参考http://php.net/manual/en/function.call-user-func-array.php,他们在这里提到了如何在call_user_func_array
中调用父类函数。
示例:强>
call_user_func_array(array($this, 'parent::__construct'), $args);
修改1
见下面的例子:
class BaseClass {
protected function __construct() {
print "In BaseClass constructor<br />";
}
}
//class SubClass extends BaseClass {
// function __construct() {
// parent::__construct();
// print "In SubClass constructor<br />";
// }
//}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
function test(){
echo 'in test';
}
}
call_user_func_array(array('OtherSubClass', 'test'), array()); //
// In BaseClass constructor
$obj = new OtherSubClass(); //produce fatel error
<强>输出:强>
Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method OtherSubClass::test() should not be called statically in /var/www/html/test/test1.php on line 22
in test
Fatal error: Call to protected BaseClass::__construct() from invalid context in /var/www/html/test/test1.php on line 24
因此,如果字符串在call_user_func_array
函数中给出,则它产生输出但是具有严格的标准错误,并且在创建产生致命错误的类的新对象时。
答案 2 :(得分:1)
请记住,构造函数是在创建新对象时调用的特殊方法。 call_user_func_array()
不会调用任何构造函数,因为它不会创建任何新对象。
City - Country
Country - Language
根据您的问题,我假设call_user_func_array(array($controller, $route['action']), $data);
是$controller
类型的对象。它已经在您将其传递给AuthController
时创建。在创建对象时调用了构造函数。
但是等一下?什么构造函数?类call_user_func_array()
没有定义任何构造函数。它继承了AuthController
的父类构造函数。因为它不是公共的,所以无法调用它并且不会创建对象;该脚本会抛出致命错误并退出。
您可以将protected
的可见性更改为Controller::__construct()
(这样可以实例化这两个类,并为两者运行public
的构造函数)。或者,如果您希望保持类Controller
由于某种原因不可实例化,则为类Controller
定义public
构造函数,该构造函数调用类AuthController
的受保护构造函数来完成工作:
Controller