Php 按“检查实例类”;如果;vs.“;方法“;

Php 按“检查实例类”;如果;vs.“;方法“;,php,oop,Php,Oop,在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;

在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 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不仅在泄漏,而且现在是个骗子。尽管方法签名声明它接受任何数据类型的参数,但它不是真的,因为当参数不是特定类型时会引发异常始终注意泄漏

由于上述尝试已被取消,让我们检查第二个。 您正在添加一个新方法
mapEntity
,该方法正确地提示所需的数据类型。另一种方法是
map()
,用于填充接口

这似乎是
map()
方法的唯一目的。它可能不会被使用,因为您在实现专用方法时遇到了麻烦。您实现了一个可能不会使用的方法,该方法会将

不应强制任何客户端依赖于它不使用的方法


我觉得用方法比较好。但我会在这里等待一些详细的答案。@nbin目前我也在使用该方法,但唯一的原因是我不需要编写异常消息,并且仍然有php生成错误的完整详细原因。我已经更新了问题,并说明了我想如何使用类来进行更多解释,为什么我不能扔掉那个接口和映射方法呢。我相信现在可以用这个方法了。无论如何,非常感谢你的解释:)不客气。序列化程序真的会接受多种类型的映射器吗?如果是专门针对EntityMapper的,您可以在序列化程序中键入提示。如果它可以处理多个映射器,您可以分解序列化程序,使用类似于
EntityApperserializer
的东西。太多的抽象也可能出现在你的方式中,所以在选择合适的方法时,考虑你的项目的复杂性。嗯,将会有很多的地图绘制者,曾经的模型会有一个和集合,谢谢。我相信现在这是一个很好的解决方案,如果将来遇到麻烦,我会把它分解成更小的类,如您所描述的:)仍然谢谢,我感谢您的帮助:)