它始于我在各处执行空值检查以确保我的交互者具有必要的实体时。幸运的是,我碰到了这篇文章,该文章指出不允许实体处于无效状态do the check in your constructor。现在,我的交互器使用protected static $request
来明确说明它们需要哪些实体,然后在实例化期间将其传递。我选择了static,因此可以在创建Interactor实例之前进行检查。
abstract class Interactor {
protected static $request = [];
protected $entities = [];
final public function __construct(Entity ...$entities) {
$this->setEntities(...$entities);
$this->checkEntities();
}
final private function setEntities(Entity ...$entities) {
foreach($entities as $entity) {
$this->setEntity($entity);
}
}
final private function setEntity(Entity $entity){
$className = get_class($entity);
if (!in_array($className, static::$request)){
throw new Exception("Not a requested entity");
}
$this->entities[$className] = $entity;
}
final private function checkEntities(){
if (count(static::$request) != count($this->entities))
throw new Exception("Entity mismatch");
foreach(static::$request as $index=>$name) {
if (!array_key_exists($name, $this->entities))
throw new Exception("Missing requested entity ($name)");
if (!is_a($this->entities[$name], $name))
throw new Exception("Not the specified entity");
}
}
final public static function getRequest(){
return array_values(static::$request);
}
}
好的,现在我只需要在一个位置进行检查,而不必担心在函数开始时执行空检查。我现在所要解决的问题是我的Interactor正在对照静态类名请求数组检查类名。因此,当我在测试过程中对模拟实体进行DI时,我的父Interactor会抛出一个异常,指出它不在预先批准的列表中。
下面是简化的国际象棋示例,以进行演示:
class Chess extends Interactor {
protected static $request = ['Piece','Engine','Board'];
}
然后我们有了实体:
abstract class Entity {}
class Piece extends Entity {}
class Engine extends Entity {}
class Board extends Entity {}
最后是我们的测试:
class ChessTest extends TestCase {
function setUp(){
$this->piece = $this->getMockBuilder(Piece::class)->getMock();
$this->engine = $this->getMockBuilder(Engine::class)->getMock();
$this->board = $this->getMockBuilder(Board::class)->getMock();
$this->chess = new Chess($this->piece, $this->engine, $this->board);
}
function testCanSetup(){
$this->assertTrue(
is_a($this->chess, Chess::class)
);
}
}
哪个抛出异常:不请求交互器接收实体(Mock_Piece_faaf8b14)
当然,Mock_Piece_faaf8b14不会出现在我们的static::$request
数组中,因此注定会引发异常。
到目前为止,我想出的解决方法是将其包含在Entity中:
public function getClassName(){
return get_called_class();
}
然后在Interactor->setEntity($entity)
中而不是使用get_class($entity)
,我会使用$entity->getClassName()
来简化模拟。
我认为我创建Interactor的方式与前面提到的帖子的内容是内联的,只采用了构造函数中的实体。但是,当我注入模拟实体时,一切都感到与众不同。
1)有没有办法避免在我的实体中getClassName()
?
2)我可以模拟的实体中是否有某些东西在get_class()
中被调用?
谢谢您的帮助!
答案 0 :(得分:1)
您正在检查类的名称是否为$request
数组中的键之一。事实并非如此。数组中的键是数字0、1、2,因此会引发异常。我认为您想改用in_array
。
尽管与此同时,它仍然无法通过模拟传递,因为您正在检查类名是否在$request
中。因此,该名称也将根本不存在,并且仍然会引发异常。
如果您的Interactor
类正在做的是确保将正确的对象传递给构造函数,为什么不只使用PHP的本机类型提示呢?
您的Chess
类变为:
class Chess {
public function __construct(Piece $piece, Engine $engine, Board $board) { }
}
PHP将确保传入的对象具有正确的类型,并允许您模拟它们以进行测试。
您将获得所需的类型检查,而根本不需要使用getClassName()
。