简体   繁体   English

这是使用 php 7 断言的类不变性的有效示例吗?

[英]Is this a valid example of Class invariances using php 7 asserts?

I am trying to understanding a little best the Class Invariances used by Liskov Principle.我试图更好地理解 Liskov 原则使用的类不变性。

I know that some languages like D have native support to invariant , but, using asserts in PHP I've tried combining magic methods and assert:我知道像 D这样的一些语言对 invariant 有本机支持,但是,在 PHP 中使用断言我尝试结合魔术方法和断言:

<?php

class Person {
    protected string $name;
    protected string $nickName;
    protected function testContract(){
        assert(($this->name != $this->nickName));
    }
    public function __construct(string $name, string $nickName){
        $this->name = $name;
        $this->nickName = $nickName;
    }
    public function __set($name, $value){
        $this->testContract();
        $this->$name = $value;
    }
    public function __get($name){
        $this->testContract();
        return $this->$name;
    }
}

class GoodPerson extends Person {
    public function getFullName(){
        return $this->name." ".$this->nickName. "!!!";
    }
}

class BadPerson extends Person {
    protected function testContract(){
        assert(($this->name != ""));
    }
}

$gp = new GoodPerson("João", "Joãozinho");
echo $gp->nickName;
echo $gp->getFullName();
$bp = new BadPerson("João", "João");
echo $bp->nickName;
  • Can I use assert to create a Contract?我可以使用 assert 来创建合约吗?
  • Is BadPerson a valid example to Liskov's Class Invariance violation on inheritance ? BadPerson 是 Liskov 在继承上违反类不变性的有效例子吗?
  • Is GoodPerson a valid example to Liskov's Classe Invariance? GoodPerson 是 Liskov 的类不变性的有效例子吗?

Can I use assert to create a Contract?我可以使用 assert 来创建合约吗?

No

From PHP Documentation来自PHP 文档

  • Assertions should be used as a debugging feature only断言应仅用作调试功能
  • Assertions should not be used for normal runtime operations like input parameter checks断言不应用于正常的运行时操作,如输入参数检查

Is BadPerson a valid example to Liskov's Class Invariance violation on inheritance? BadPerson 是 Liskov 在继承上违反类不变性的有效例子吗?

Yes是的

Preconditions cannot be strengthened in a subtype.不能在子类型中加强先决条件。

But your code doesn't make any sense但是你的代码没有任何意义

First your testContract method will only be invoked if you try to set or get a dynamic property and it will check for the parameters you passed through the constructor首先,您的testContract方法只会在您尝试设置或获取动态属性时被调用,并且它将检查您通过constructor传递的参数

public function __set($name, $value){
    $this->testContract();
    $this->$name = $value;
}

Here you basically test the constructor parameters but in the magic method ( __set )在这里,您基本上测试了构造函数参数,但在魔术方法中( __set

So in order to make that check works you need to invoke the __set like this因此,为了使该检查有效,您需要像这样调用__set

$gp = new BadPerson("João", "Joãozinho");
$gp->name = ''; // This line here invokes __set magic method

So what you really need to do is get rid of testContract and put the check inside the base class constructor.所以你真正需要做的是摆脱testContract并将检查放在基类构造函数中。 Why?为什么? because your properties are protected so the only opportunity that clients have for setting them is through the constructor因为您的属性受到protected所以客户设置它们的唯一机会是通过构造函数

public function __construct(string $name, string $nickName){
    if ($name != "" && $name != $nickName)
        throw new Exception('Name must not be empty and must not equal Nickname');

    $this->name = $name;
    $this->nickName = $nickName;
}

Is GoodPerson a valid example to Liskov's Classe Invariance? GoodPerson 是 Liskov 的类不变性的有效例子吗?

Yes是的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM