说我有以下控制器结构:
class Controller {
public function __construct(){
$this->accessControl();
}
}
class Account extends Controller {
public function __construct(User $user){
parent::__construct();
$this->user = $user;
}
}
如何要求其他开发人员在其子控制器中显式调用parent::__construct()
?它包含访问控制等关键的东西
到目前为止,我决定将所有函数从父构造函数包装到init()
方法中,该方法将initialized
属性设置为TRUE,然后在路由器中检查此属性。如果它不是TRUE - 抛出异常。
public $initialized = false;
class Controller {
public function __construct(){
$this->init();
}
}
protected function init(){
$this->accessControl();
$this->initialized = true;
}
class Router {
public function process($path){
$controller = new User();
if(!$controller instanceof Controller || !$controller->initialized){
throw new Exception('Error');
}
}
}
味道不好吗?
答案 0 :(得分:2)
Symfony\Console命令需要相同,其中构造函数必须添加命令名称和定义。
They handle it like this在添加命令的单个位置。所以你在路由器中检查控制器的方法是一样的。 我得到它,而不是把责任抽象到Controller或者反思。
另一方面,应该在安全层级上检查accessControl()
,而不是在路由器中。
您使用什么框架?
您可以使用EventSubscriber和框架事件将其与路由器分离吗?
答案 1 :(得分:0)
是的,闻起来很糟糕。
如何要求其他开发人员显式调用parent :: __ construct() 他们的孩子控制员?
首先,您应该相信您的开发人员。另一个问题是如何确保所有控制器都具有访问控制。为了确保这一点,您必须通过测试覆盖所有控制器。因此,应该测试每个控制器,检查未经授权的用户是否可以访问它。
到目前为止,我决定将所有函数从父构造函数包装到 将
init()
属性设置为TRUE的initialized
方法,然后选中此项 路由器中的属性。
实际上,您的init
函数没有价值,因为您刚刚从__construct
移动了代码(现在您必须确保开发人员调用init
函数 - - 看,只改名称;))。您也可以在initialized
本身设置__construct
。
if(!$controller instanceof Controller || !$controller->initialized){ throw new Exception('Error'); }
因此,您最终会强制您的开发人员检查控制器是否已初始化,在每个地方都将使用它。
我猜你不能让代码万无一失。您必须信任开发人员做正确的事情并教育新的团队成员。当然,您应该使用测试覆盖所有代码,因为在实践中,这是确保开发人员做出正确事情的唯一方法。
有一个很好的播客,对你的问题是切实的:"Type Safety Roundtable with Ryan Tablada and Matt Machuga"。