通过 "if" 与 "method" 检查实例 class
check instance class by "if" vs. "method"
在 php 中你不能重写方法所以这样的事情是不可能的,因为声明不兼容。
class Entity
{}
class NotEntity
{}
abstract class Mapper
{
abstract public function map($data);
}
class EntityMapper extends Mapper
{
public function map(Entity $data)
{
return true;
}
}
问题是:什么是更好的解决方案?
IF:
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 中的方法可以重写,但不能重载。但是在您的第一个示例中,您既没有尝试覆盖也没有重载该方法。
你所做的是,实现接口所需的方法(在你的例子中是抽象 class),但方法签名不同于接口中给出的约束。这就是 PHP 抱怨的原因。
您解决问题的第一个尝试是使用正确的签名实现 map()
方法。这里的问题在于方法体。您正在明确检查类型。您的 API 不仅在泄密,而且现在是个骗子。尽管方法签名声明它接受任何数据类型的参数,但事实并非如此,因为当参数不是特定类型时会抛出异常。 时刻注意泄漏。
既然上面的尝试被排除了,让我们来看看第二个。
您正在添加一个新方法 mapEntity
,它正确地键入提示所需的数据类型。另一种方法 map()
是用来填充接口的。
看来这就是map()
方法的唯一用意了。它可能不会被使用,因为您经历了为此实现专用方法的麻烦。您实现了一个可能不会被使用的方法,它打破了 Interface Seggregation Principle,它简单地分解为:
no client should be forced to depend on methods it does not use
<?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));
我建议您引入一个新接口,该接口对其接受的类型更加具体。您的新摘要 class 将是 EntityMapper
,它明确要求传递 Entity
。派生的 classes 现在符合接口。
如果您发现自己在处理数据类型的后代问题时苦苦挣扎,请考虑分解您的接口并强制其对其参数进行更多描述。
在 php 中你不能重写方法所以这样的事情是不可能的,因为声明不兼容。
class Entity
{}
class NotEntity
{}
abstract class Mapper
{
abstract public function map($data);
}
class EntityMapper extends Mapper
{
public function map(Entity $data)
{
return true;
}
}
问题是:什么是更好的解决方案?
IF:
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 中的方法可以重写,但不能重载。但是在您的第一个示例中,您既没有尝试覆盖也没有重载该方法。
你所做的是,实现接口所需的方法(在你的例子中是抽象 class),但方法签名不同于接口中给出的约束。这就是 PHP 抱怨的原因。
您解决问题的第一个尝试是使用正确的签名实现 map()
方法。这里的问题在于方法体。您正在明确检查类型。您的 API 不仅在泄密,而且现在是个骗子。尽管方法签名声明它接受任何数据类型的参数,但事实并非如此,因为当参数不是特定类型时会抛出异常。 时刻注意泄漏。
既然上面的尝试被排除了,让我们来看看第二个。
您正在添加一个新方法 mapEntity
,它正确地键入提示所需的数据类型。另一种方法 map()
是用来填充接口的。
看来这就是map()
方法的唯一用意了。它可能不会被使用,因为您经历了为此实现专用方法的麻烦。您实现了一个可能不会被使用的方法,它打破了 Interface Seggregation Principle,它简单地分解为:
no client should be forced to depend on methods it does not use
<?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));
我建议您引入一个新接口,该接口对其接受的类型更加具体。您的新摘要 class 将是 EntityMapper
,它明确要求传递 Entity
。派生的 classes 现在符合接口。
如果您发现自己在处理数据类型的后代问题时苦苦挣扎,请考虑分解您的接口并强制其对其参数进行更多描述。