我有一个很奇怪的问题,我不知道这是否是由于call_user_func_array
。
在 PHP 5.4 上测试
当前设置
例如,我有一个扩展名为 Controller
的基本控制器的 AuthController
类:
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 构造函数?
我会在这里在黑暗中试一试,并说你实际上是在这样做:
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);
// ^^^
作为PHP文档在 http://php.net/manual/en/language.oop5.decon.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
那么它正在产生输出,但具有严格的标准错误,并且在创建产生致命错误的类的新对象时
请记住,构造函数是在创建新对象时调用的特殊方法。 call_user_func_array()
不调用任何构造函数,因为它不会创建任何新对象。
call_user_func_array(array($controller, $route['action']), $data);
从你的问题中,我假设$controller
是 AuthController
类型的对象。当您将其传递给call_user_func_array()
时,它已经创建。它的构造函数是在创建对象时调用的。
但是等一下?什么构造函数?类AuthController
不定义任何构造函数。它继承了protected
的父类构造函数。因为它不是公共的,所以不能调用它,也不会创建对象;脚本引发致命错误并退出。
您可以将Controller::__construct()
的可见性更改为public
(这样就可以实例化这两个类,并且Controller
的构造函数为这两个类运行(。或者,如果由于某种原因希望类Controller
不可实例化,则可以为类AuthController
定义一个public
构造函数,该构造函数调用类Controller
的受保护构造函数来完成这项工作:
class AuthController extends Controller
{
public function __construct()
{
parent::__construct();
}
// other methods here...
}