Является ли это действительным примером инвариантов класса, использующих утверждения php 7? - PullRequest
0 голосов
/ 13 января 2020

Я пытаюсь немного лучше понять инварианты классов, используемые принципом Лискова.

Я знаю, что некоторые языки , такие как D, имеют встроенную поддержку инварианта , но, используя утверждения в PHP Я пытался объединить маги c методы и assert:

<?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;
  • Могу ли я использовать assert для создания Контракта?
  • Является ли BadPerson верным примером нарушения инвариантности классов Лискова при наследовании?
  • Является ли GoodPerson верным примером инвариантности классов Лискова?

1 Ответ

1 голос
/ 13 января 2020

Могу ли я использовать assert для создания Контракта?

Нет

От PHP Документация

  • Утверждения должны использоваться только в качестве функции отладки
  • Утверждения не должны использоваться для обычных операций времени выполнения, таких как проверки входных параметров

Является ли BadPerson допустимым примером для класса инвариантности Лискова нарушение наследования?

Да

Предварительные условия не могут быть усилены в подтипе.

Но ваш код не имеет никакого смысла

Сначала ваш метод testContract будет вызван, только если вы попытаетесь установить или получить свойство динамического c, и он проверит параметры, которые вы передали через constructor

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

Здесь вы в основном тестируете параметры конструктора, но в методе magi c (__set)

Итак, чтобы эта проверка работала, вам нужно вызвать __set, например,

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

Итак, что вам действительно нужно сделать, это избавиться от testContract и р проверка внутри конструктора базового класса. Почему? потому что ваши свойства 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;
}

Является ли GoodPerson верным примером Лискова Classe Invariance?

Да

...