通过“if”与“method”检查实例类

时间:2015-03-19 08:33:44

标签: php oop

在php中你不能覆盖方法所以这样的东西是不可能的,因为decalaration是不兼容的。

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());

1 个答案:

答案 0 :(得分:2)

PHP中的方法可以被覆盖,但它们不能被重载。但是在你的第一个例子中,你既不会覆盖,也不会重载该方法。

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

首次尝试解决问题的方法是使用map()方法实现正确的签名。这里的问题在于方法体。您正在明确检查类型。您的API不仅泄漏,而且现在是骗子。尽管方法签名声明它接受任何数据类型的参数,但它不是真的,因为当参数不是某种类型时会抛出异常。 始终注意泄漏

由于上述尝试被踢出,让我们检查第二个。 您正在添加一个新方法mapEntity,它正确地键入提示所需的数据类型。另一种方法map()可用于填充界面。

这似乎是map()方法的唯一目的。它可能不会被使用,因为你经历了为此实现专用方法的麻烦。你实现了一个可能不会被使用的方法,它打破了Interface Seggregation Principle,它简单地分解为:

  

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

<?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。派生类现在符合接口。

如果你发现自己在数据类型的后代上挣扎,那么考虑打破你的界面并强迫它更多地描述它的论点。