通过“检查实例类”;如果“;与“;方法”;


check instance class by "if" vs. "method"

在php中,您不能覆盖方法,所以这样的事情是不可能的,因为decaration是不兼容的。

class Entity
{}
class NotEntity
{}
abstract class Mapper
{
    abstract public function map($data);
}
class EntityMapper extends Mapper
{
    public function map(Entity $data)
    {
        return true;
    }
}

问题是:什么是更好的解决方案?

中频:

class EntityMapper extends Mapper
{
    /**
     * @param Entity $data
     * @return bool
     * @throws Exception
     */
    public function map($data)
    {
        if(!$data instanceof Entity) {
            throw new Exception();
        }
        return true;
    }
}
$mapper = new EntityMapper();
var_dump($mapper->map(new NotEntity())); //FATAL ERROR: Uncaught Exception

方法:

class EntityMapper extends Mapper
{
    /**
     * @param Entity $data
     * @return bool
     */
    public function map($data)
    {
        return $this->mapEntity($data);
    }
    private function mapEntity(Entity $entity)
    {
        return true;
    }
}
$mapper = new EntityMapper();
var_dump($mapper->map(new NotEntity())); //Catchable fatal error: Argument 1 passed to EntityMapper::mapEntity() must be an instance of Entity, instance of NotEntity given

更新

这里展示的这个对象的用法只是为了演示如何获取错误。此类的预期用途如下:

class Serializer
{
    public function serialize($object, Mapper $mapper)
    {
        return $mapper->map($object);
    }
}
$serializer = new Serializer();
$serializer->serialize(new Entity(),new EntityMapper());

PHP中的方法可以被覆盖,但不能重载。但是在您的第一个示例中,您既没有试图覆盖该方法,也没有重载该方法。

您所做的是实现接口所需的方法(在您的情况下是抽象类),但使用与接口中给定的约束不同的方法签名。这就是PHP抱怨的原因。

解决该问题的第一次尝试是使用正确的签名实现map()方法。这里的问题在于方法主体。您正在显式检查类型。您的API不仅泄漏,而且现在是个骗子。尽管方法签名声明它接受任何数据类型的参数,但事实并非如此,因为当参数不是特定类型时会引发Exception始终注意泄漏

既然上面的尝试被否决了,让我们来看看第二个。您正在添加一个新方法mapEntity,它正确地键入提示所需的数据类型。另一种方法map()用于填充接口。

这似乎是map()方法的唯一意图。它可能不会被使用,因为您遇到了实现专用方法的麻烦。您实现了一种可能不会使用的方法,它打破了接口分段原则,该原则简单地分解为:

任何客户端都不应该被迫依赖于不使用的方法

<?php
class Entity
{}
class NotEntity
{}
abstract class EntityMapper
{
    public abstract function map( Entity $data);
}
class DatabaseEntityMapper extends EntityMapper
{
    public function map(Entity $data)
    {
        // Do DB Stuff
        return true;
    }
}
class ArrayEntityMapper extends EntityMapper
{
    public function map(Entity $data)
    {
        // Do Array Stuff
        return true;
    }
}
$em = new ArrayEntityMapper();
var_dump($em->map(new Entity));

我建议您引入一个新的接口,它接受的类型更具体一些。新的抽象类将是EntityMapper,它明确要求传递Entity。派生类现在符合接口。

如果您发现自己在处理数据类型的派生,请考虑分解您的接口,并强制它对其参数进行更多描述。

相关文章: