Это гостевой выпуск Пятиминутки PHP — ведёт Кирилл Сулимовский.

(function(){
var data = {
«addon_key»:»net.veniture.confluence.cloud.macrosuite»,
«uniqueKey»:»net.veniture.confluence.cloud.macrosuite__easy-html6030694237622860366″,
«key»:»easy-html»,
«moduleType»:»dynamicContentMacros», «moduleLocation»:»content», «cp»:»/wiki»,
«general»:»»,
«w»:»100%»,
«h»:»100%»,
«url»:»https://macrosuite.cloud.veniture.net/html?macroId=5d466910-45f4-4208-a89b-bd12e29e7515&pageId=106529405&pageVersion=3&xdm_e=https%3A%2F%2Fmishaikon.atlassian.net&xdm_c=channel-net.veniture.confluence.cloud.macrosuite__easy-html6030694237622860366&cp=%2Fwiki&xdm_deprecated_addon_key_do_not_use=net.veniture.confluence.cloud.macrosuite&lic=none&cv=1.1018.0&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI1YmIzNGM2ODU5ZDg4MTEzYTM3MzkyZWYiLCJxc2giOiI4YmFkYzllYjE5MzhkYjk4OTZiOWI0MmI5OGE5ODY4ZjIzZTZjNmJhNWQzMmEzYzBlOWE5ZmE2YWQ1Y2Y1ZjQ1IiwiaXNzIjoiOWU3NWMxNmEtNmFkYi0zZDVkLTk2ZjgtZDJjY2E2ZDQ5ZDAwIiwiY29udGV4dCI6e30sImV4cCI6MTYyNTQ3NjI4NSwiaWF0IjoxNjI1NDc2MTA1fQ.w5ppKiLTcy-Y91covOd3mMjWsK89Y25OZghjnmc_uQs»,
«contextJwt»: «eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI1YmIzNGM2ODU5ZDg4MTEzYTM3MzkyZWYiLCJxc2giOiJjb250ZXh0LXFzaCIsImlzcyI6IjllNzVjMTZhLTZhZGItM2Q1ZC05NmY4LWQyY2NhNmQ0OWQwMCIsImNvbnRleHQiOnsiY29uZmx1ZW5jZSI6eyJtYWNybyI6eyJvdXRwdXRUeXBlIjoiZW1haWwiLCJoYXNoIjoiNWQ0NjY5MTAtNDVmNC00MjA4LWE4OWItYmQxMmUyOWU3NTE1IiwiaWQiOiI1ZDQ2NjkxMC00NWY0LTQyMDgtYTg5Yi1iZDEyZTI5ZTc1MTUifSwiY29udGVudCI6eyJ0eXBlIjoicGFnZSIsInZlcnNpb24iOiIzIiwiaWQiOiIxMDY1Mjk0MDUifSwic3BhY2UiOnsia2V5IjoiV0lLSSIsImlkIjoiODIyNDc5NCJ9fX0sImV4cCI6MTYyNTQ3NzAwNSwiaWF0IjoxNjI1NDc2MTA1fQ.s5yIoYJkRr6z9-yWcBsz892DPSSKxhZ1Wv6uZHiqOEc», «structuredContext»: «{»confluence»:{»macro»:{»outputType»:»email»,»hash»:»5d466910-45f4-4208-a89b-bd12e29e7515»,»id»:»5d466910-45f4-4208-a89b-bd12e29e7515»},»content»:{»type»:»page»,»version»:»3»,»id»:»106529405»},»space»:{»key»:»WIKI»,»id»:»8224794»}}}»,
«contentClassifier»:»content»,
«productCtx»:»{»page.id»:»106529405»,»macro.hash»:»5d466910-45f4-4208-a89b-bd12e29e7515»,»space.key»:»WIKI»,»user.id»:»5bb34c6859d88113a37392ef»,»page.type»:»page»,»content.version»:»3»,»page.title»:»(L) u041fu0440u0438u043du0446u0438u043f u043fu043eu0434u0441u0442u0430u043du043eu0432u043au0438 u0411u0430u0440u0431u0430u0440u044b u041bu0438u0441u043au043eu0432»,»macro.body»:»»,»: = | RAW | = :»:»theme={\»label\»:\»solarized_dark\»,\»value\»:\»solarized_dark\»}|contentByMode={\»html\»:\»u003ciframe width=\\\»100%\\\» height=\\\»166\\\» scrolling=\\\»no\\\» frameborder=\\\»no\\\» allow=\\\»autoplay\\\» src=\\\»https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1035321238&color=ff5500&hide_related=true&show_comments=false&show_teaser=false\\\»u003eu003c/iframeu003eu003cdiv style=\\\»font-size: 10px; color: #cccccc;line-break: anywhere;word-break: normal;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; font-family: Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif;font-weight: 100;\\\»u003eu003ca href=\\\»https://soundcloud.com/5minphp\\\» title=\\\»u041fu044fu0442u0438u043cu0438u043du0443u0442u043au0430 PHP\\\» target=\\\»_blank\\\» style=\\\»color: #cccccc; text-decoration: none;\\\»u003eu041fu044fu0442u0438u043cu0438u043du0443u0442u043au0430 PHPu003c/au003e u00b7 u003ca href=\\\»https://soundcloud.com/5minphp/episode88\\\» title=\\\»u041fu0440u0438u043du0446u0438u043f u043fu043eu0434u0441u0442u0430u043du043eu0432u043au0438 u0411u0430u0440u0431u0430u0440u044b u041bu0438u0441u043au043eu0432\\\» target=\\\»_blank\\\» style=\\\»color: #cccccc; text-decoration: none;\\\»u003eu041fu0440u0438u043du0446u0438u043f u043fu043eu0434u0441u0442u0430u043du043eu0432u043au0438 u0411u0430u0440u0431u0430u0440u044b u041bu0438u0441u043au043eu0432u003c/au003eu003c/divu003e\»,\»javascript\»:\»\»,\»css\»:\»\»}»,»space.id»:»8224794»,»contentByMode»:»{\»html\»:\»u003ciframe width=\\\»100%\\\» height=\\\»166\\\» scrolling=\\\»no\\\» frameborder=\\\»no\\\» allow=\\\»autoplay\\\» src=\\\»https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1035321238&color=ff5500&hide_related=true&show_comments=false&show_teaser=false\\\»u003eu003c/iframeu003eu003cdiv style=\\\»font-size: 10px; color: #cccccc;line-break: anywhere;word-break: normal;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; font-family: Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif;font-weight: 100;\\\»u003eu003ca href=\\\»https://soundcloud.com/5minphp\\\» title=\\\»u041fu044fu0442u0438u043cu0438u043du0443u0442u043au0430 PHP\\\» target=\\\»_blank\\\» style=\\\»color: #cccccc; text-decoration: none;\\\»u003eu041fu044fu0442u0438u043cu0438u043du0443u0442u043au0430 PHPu003c/au003e u00b7 u003ca href=\\\»https://soundcloud.com/5minphp/episode88\\\» title=\\\»u041fu0440u0438u043du0446u0438u043f u043fu043eu0434u0441u0442u0430u043du043eu0432u043au0438 u0411u0430u0440u0431u0430u0440u044b u041bu0438u0441u043au043eu0432\\\» target=\\\»_blank\\\» style=\\\»color: #cccccc; text-decoration: none;\\\»u003eu041fu0440u0438u043du0446u0438u043f u043fu043eu0434u0441u0442u0430u043du043eu0432u043au0438 u0411u0430u0440u0431u0430u0440u044b u041bu0438u0441u043au043eu0432u003c/au003eu003c/divu003e\»,\»javascript\»:\»\»,\»css\»:\»\»}»,»macro.truncated»:»false»,»content.type»:»page»,»output.type»:»email»,»page.version»:»3»,»user.key»:»8a7f808a78f05f9f0178f48910920162»,»content.id»:»106529405»,»macro.id»:»5d466910-45f4-4208-a89b-bd12e29e7515»,»theme»:»{\»label\»:\»solarized_dark\»,\»value\»:\»solarized_dark\»}»}»,
«timeZone»:»Europe/Moscow»,
«origin»:»https://macrosuite.cloud.veniture.net»,
«hostOrigin»:»https://mishaikon.atlassian.net»,
«sandbox»:»allow-downloads allow-forms allow-modals allow-popups allow-scripts allow-same-origin allow-top-navigation-by-user-activation allow-storage-access-by-user-activation», «apiMigrations»: {
«gdpr»: true
}
}
;
if(window.AP && window.AP.subCreate) {
window._AP.appendConnectAddon(data);
} else {
require([‘ac/create’], function(create){
create.appendConnectAddon(data);
});
}
}());

(звезда) Также порекомендую подписаться на телеграм канал Кирилла: (2)

Принцип подстановки Барбары Лисков

❓Почему у многих возникают проблемы с этим принципом? Если взять не заумное , а более простое объяснение, то оно звучит так: (1)

«Наследующий класс должен дополнять, а не замещать поведение базового класса».

Звучит логично и понятно, расходимся. но блин, как этого добиться? Почему-то многие просто пропускают мимо ушей следующие строки, которые как раз отлично объясняют что нужно делать.

Рассмотрим выражение «Предусловия не могут быть усилены в подклассе»

(warning) Другими словами дочерние классы не должны создавать больше предусловий, чем это определено в базовом классе, для выполнения некоторого бизнесового поведения. Вот несложный пример:

<?php

class Customer
{
    protected float $account = 0;

    public function putMoneyIntoAccount(int|float $sum): void
    {
        if ($sum < 1) {
            throw new Exception('Вы не можете положить на счёт меньше 1$');
        }

        $this->account += $sum;
    }
}

class  MicroCustomer extends Customer
{
    public function putMoneyIntoAccount(int|float $sum): void
    {
        if ($sum < 1) {
            throw new Exception('Вы не можете положить на счёт меньше 1$');
        }

        // Усиление предусловий
        if ($sum > 100) { 
            throw new Exception('Вы не можете положить на больше 100$');
        }

        $this->account += $sum;
    }
}

(минус) Добавление второго условия как раз является усилением. Так делать не надо!

Контравариантность также можно отнести к данному приниципу. Она касается параметров функции, которые может ожидать подкласс. Подкласс может увеличить свой диапазон параметров, но он должен принять все параметры, которые принимает родительский.

  • Этот пример показывает, как расширение допускается, потому что метод Bar->process() принимает все типы параметров, которые принимает родительский метод.

<?php

class Foo
{
    public function process(int|float $value)
    {
       // some code
    }
}

class Bar extends Foo
{
    public function process(int|float|string $value)
    {
        // some code
    }
}
  • В этом примере дочерний класс может принимать более широкий спектр объектов, которые могут быть наследованы от Money, не только Dollars.

<?php

class Money {}
class Dollars extends Money {}

class Customer
{
    protected Money $account;

    public function putMoneyIntoAccount(Dollars $sum): void
    {
        $this->account = $sum;
    }
}

class  VIPCustomer extends Customer
{
    public function putMoneyIntoAccount(Money $sum): void
    {
        $this->account = $sum;
    }
}

Таким образом, мы не добавляем дополнительных проверок, не делаем условия жестче и наш дочерний класс уже ведёт себя более предсказуемо.

В следующих постах мы также рассмотрим постуловия и ковариантность 😉

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

То есть подклассы должны выполнять все постусловия, которые определены в базовом классе. Постусловия проверяют состояние возвращаемого объекта на выходе из функции. Вот такой пример.

<?php

class Customer
{
    protected Dollars $account;

    public function chargeMoney(Dollars $sum): float
    {
        $result = $this->account - $sum->getAmount();

        if ($result < 0) { // Постусловие
            throw new Exception();
        }

        return $result;
    }
}

class  VIPCustomer extends Customer
{
    public function chargeMoney(Dollars $sum): float
    {
        $result = $this->account - $sum->getAmount();

        if ($sum < 1000) { // Добавлено новое поведение
            $result -= 5;
        }

        // Пропущено постусловие базового класса

        return $result;
    }
}

(минус) Условное выражение проверяющее результат является постусловием в базовом классе, а в наследнике его уже нет. Не делай так!

Сюда-же можно отнести и ковариантность, которая позволяет объявлять в методе дочернего класса типом возвращаемого значения подтип того типа, который возвращает родительский метод.

Короче, в данном примере:

<?php

class Image {}
class JpgImage extends Image {}

class Renderer
{
    public function render(): Image
    {
    }
}

class PhotoRenderer extends Renderer
{
    public function render(): JpgImage
    {
    }
}

в методе render() дочернего класса, JpgImage объявлен типом возвращаемого значения, который в свою очередь является подтипом Image, который возвращает метод родительского класса Renderer.

(warning) Таким образом в дочернем классе мы сузили возвращаемое значение. Не ослабили. А усилили 🙂

(warning) Все условия базового класса — также должны быть сохранены и в подклассе.

Инварианты — это некоторые условия, которые остаются истинными на протяжении всей жизни объекта. Как правило, инварианты передают внутреннее состояние объекта.

Например типы свойств базового класса не должны изменяться в дочернем.

class Wallet

{

protected float $amount;

// тип данного свойства не должен изменяться в подклассе

}

Здесь также стоит упомянуть исторические ограничения («правило истории»):

(warning) Подкласс не должен создавать новых мутаторов свойств базового класса.

Если базовый класс не предусматривал методов для изменения определенных в нем свойств, подтип этого класса так же не должен создавать таких методов. Иными словами, неизменяемые данные базового класса не должны быть изменяемыми в подклассе.

(минус) С точки зрения класса Deposit поле не может быть меньше нуля. А вот производный класс VipDeposit, добавляет метод для изменения свойства account, поэтому инвариант класса Deposit нарушается. Такого поведения следует избегать. В таком случае стоит рассмотреть добавление мутатора в базовый класс.

23.04.2021 | Автор Petr Myazin


Источники:

(1) https://5minphp.ru/episode88/

(2) Телеграм канал спикера: https://t.me/beerphp

Tags

Нет комментариев

Добавить комментарий

Ваш адрес email не будет опубликован.

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.