当前位置: 首页 > 面试题库 >

PHP对Java样式类的泛型有答案吗?

谷泳
2023-03-14
问题内容

在PHP中构建MVC框架后,我遇到了一个问题,可以使用Java样式泛型轻松解决。抽象的Controller类可能看起来像这样:

abstract class Controller {

abstract public function addModel(Model $model);

在某些情况下,Controller类的子类只能接受Model的子类。例如,ExtendedController应该只将ReOrderableModel接受到addModel方法中,因为它提供了ExtendedController需要访问的reOrder()方法:

class ExtendedController extends Controller {

public function addModel(ReOrderableModel $model) {

在PHP中,继承的方法签名必须完全相同,因此即使类继承了超类中暗示的类类型,也不能将类型提示更改为其他类。在Java中,我只需这样做:

abstract class Controller<T> {

abstract public addModel(T model);


class ExtendedController extends Controller<ReOrderableModel> {

public addModel(ReOrderableModel model) {

但是PHP没有泛型支持。是否有任何解决方案仍将遵循OOP原则?

编辑
我知道PHP根本不需要类型提示,但是它可能是糟糕的OOP。首先,从接口(方法签名)尚不清楚应接受哪种对象。因此,如果另一个开发人员想要使用该方法,则很明显,需要类型X的对象,而不必通过无效的封装(破坏了信息隐藏原理)来查看实现(方法主体)。其次,由于没有类型安全性,因此该方法可以接受任何无效变量,这意味着到处都需要手动类型检查和异常抛出!


问题答案:

它对于以下测试用例似乎很有效(尽管它确实发出了严格警告):

class PassMeIn
{

}

class PassMeInSubClass extends PassMeIn
{

}

class ClassProcessor
{
    public function processClass (PassMeIn $class)
    {
        var_dump (get_class ($class));
    }
}

class ClassProcessorSubClass extends ClassProcessor 
{
    public function processClass (PassMeInSubClass $class)
    {
        parent::processClass ($class);
    }
}

$a  = new PassMeIn;
$b  = new PassMeInSubClass;
$c  = new ClassProcessor;
$d  = new ClassProcessorSubClass;

$c -> processClass ($a);
$c -> processClass ($b);
$d -> processClass ($b);

如果严格警告不是您真正想要的,则可以这样解决。

class ClassProcessor
{
    public function processClass (PassMeIn $class)
    {
        var_dump (get_class ($class));
    }
}

class ClassProcessorSubClass extends ClassProcessor 
{
    public function processClass (PassMeIn $class)
    {
        if ($class instanceof PassMeInSubClass)
        {
            parent::processClass ($class);
        }
        else
        {
            throw new InvalidArgumentException;
        }
    }
}

$a  = new PassMeIn;
$b  = new PassMeInSubClass;
$c  = new ClassProcessor;
$d  = new ClassProcessorSubClass;

$c -> processClass ($a);
$c -> processClass ($b);
$d -> processClass ($b);
$d -> processClass ($a);

不过,您应该记住一件事,这绝对不是OOP方面的最佳实践。如果超类可以接受特定类的对象作为方法参数,则其所有子类也应也可以接受该类的对象。防止子类处理超类可以接受的类意味着您不能使用子类代替超类,并且要100%确信它在所有情况下都可以使用。相关实践称为Liskov替代原理,它指出,除其他外,方法参数的类型只能在子类中变弱,而返回值的类型只能变强(输入只能变得更通用,输出可以仅获得更具体的信息)。

这是一个非常令人沮丧的问题,我本人已经多次尝试反对它,因此,如果在特定情况下忽略它是最好的选择,那么我建议您忽略它。但是请不要养成它的习惯,否则您的代码将开始开发各种微妙的相互依赖关系,这将是调试的噩梦(单元测试无法捕获它们,因为各个单元的行为均符合预期,这是它们之间的相互作用问题所在)。如果您确实忽略了它,那么请注释该代码以使其他人知道它,这是一个有意的设计选择。



 类似资料:
  • 问题内容: 所以我有一张地图: 我会像这样添加元素: 我有如下通用方法: 现在,这段代码可以很好地工作,并且没有编译器问题: 但是,当我尝试这样做时: 编译器向我显示以下警告:类型安全:通用方法verifyType(String,Class)的未经检查的调用verifyType(String,Class) 这让我感到困惑…请帮助… 问题答案: 更改: 至 通过仅将类型声明为“ Class”,就失去

  • 现在,当我在地图上迭代时…我能以某种方式获得每个Class1对象的类型(K,V)吗??

  • 如何获取这个类的类型?对于上下文,我使用ModelMapper,我需要类类型T从S转换为T。 背景: 我已经尝试了N种方法,其中我放置了“//一些方法来获取类型”,但没有任何效果。例如: 或

  • 嗨,我是概念数据建模的新手,目前正在研究实体关系图。只是一些我找不到答案的问题: > 我正在设计一个基于给定场景的E-R图,当我将我的答案与“模型答案”进行匹配时,它是非常不同的,特别是我在代表两个实体之间关系的菱形形状中使用的术语。我这样说对吗?只要是合乎逻辑的,代表这种关系的词语的选择就可以是任何东西? 我注意到不同的教程使用不同的表示基数的方法。有的用鱼尾纹,有的用M:N表示多对多。既然有这

  • 我不想为每个类型T编写这个方法只是为了调用getMessage()并将其传递给下一个方法。 有可能写出这样的方法吗?我只想访问ConstraintViolation接口的方法,这些方法不依赖于类型T(如字符串getMessage())。

  • 问题内容: 如果在Java中创建泛型类(该类具有泛型类型参数),则可以使用泛型方法(该方法带有泛型类型参数)吗? 考虑以下示例: 正如您对通用方法所期望的那样,我可以使用任何对象调用的实例: 但是,如果我尝试使用 不 指定泛型类型的实例,则无论传入什么,我都会调用返回, 奇怪的是,如果返回类型是通用类,它将编译(例如(实际上,这可以解释-参见下面的答案)): 此外,如果输入通用类,即使仅使用通配符