Является ли это допустимым примером инвариантности классов с использованием утверждений php 7?

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

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

1 ответ

Решение

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

Нет

Из документации PHP

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

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

да

Предпосылки нельзя усилить в подтипе.

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

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

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

Здесь вы в основном тестируете параметры конструктора, но в магическом методе (__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 действительным примером классовой инвариантности Лискова?

да

Другие вопросы по тегам