有一个Controller
类,它包含神奇的__call()
方法,该方法在传递参数时获得一个名称并创建相应名称的实例。Controller
类的属性$this
被传递给该类的构造函数,以便使用req()
函数。
例如,我使用3个类的示例从生产中重新创建了这种情况。
class One
{
public function __construct(
protected Controller $controller
) {}
public function oneTestFunc(): void {
echo $this->controller->req([__FUNCTION__, __CLASS__]);
}
}
class Two
{
public function __construct(
protected Controller $controller
) {}
public function twoTestFunc(): void {
echo $this->controller->req([__FUNCTION__, __CLASS__]);
}
}
在PHPDoc中,我定义了可以调用的方法。
/**
* Class Controller
* @method One one()
* @method Two two()
*/
class Controller
{
public function __call(string $name, array $args): mixed {
$name = ucfirst($name);
return new $name($this);
}
public function req(array $data): string {
return sprintf("Call function %s (class: %s)n", ...$data);
}
}
所有这些都是正确的。但是,在创建类的实例时,可以调用req()
函数,并且这仅在PHPDoc的预定义类中允许。
好:
$x = new Controller();
$x->one()->oneTestFunc(); // Good: Call function oneTestFunc (class: One)
$x->two()->twoTestFunc(); // Cood: Call function twoTestFunc (class: Two)
// Unacceptable! Not directly possible, the req() function is only for predefined classes.
$x->req(['click', 'clack']);
Q: 我该如何避免这种情况?创建一个特性以便在预定义的类中使用,或者在Controller
类上制作一个包装,并从中继承?同志们,在这种情况下,你们有什么建议?
您可以使用特征。特性专门用于代码重用和控制,而不需要任何类型的类继承。trait可以帮助您控制函数流,并从扩展您使用trait的类的类中收集信息,而不是扩展一个类并收集它的所有特性(有些特性可能是不必要的(。
特性示例:
namespace App;
trait Request
{
public function req(Array $data): string
{
return sprintf("Call function %s (class: %s)n", ...$data);
}
}
在第一类和第二类中使用trait,它应该有效:
use AppRequest;
class One
{
use Request;
}
class Two
{
use Request;
}
如果不使用自动加载,也可以要求使用特征文件。