#7.18 php ООП Объявление типов.Совместимость типов при передаче объектов в функцию. Совместимость при переопределении методов

Объявление типов

Для аргументов функций и методов классов, возвращаемых значений и, начиная с PHP 7.4.0, для свойств классов могут использоваться объявления типов, например

function Example(string $text)

Объявление типов используется во время исполнения программы для проверки того, что значения имеют именно тот тип, который для них указан. В противном случае будет выброшено исключение TypeError. При объявлении типа может быть указан любой тип данных, кроме resource.

Совместимость базового и производного классов при передаче объектов в функцию

Объект производного класса может использоваться везде вместо объекта базового класса, в частности, при передаче в функцию:

<?php
class Animal
{
    protected $name;

    public function __construct($name)
    {
        $this->name = $name;
    }   

    public function get_name()
    {
        return $this->name; 
    }
}

class Lion extends Animal
{
}

function print_name(Animal $obj)
{
    echo $obj->get_name();
}

$lion = new Lion("Бонифаций");
print_name($lion); 

Несмотря на то, что в качестве типа параметра $obj указан класс Animal передача объекта производного класса Lion не приведет к ошибке.

Совместимость при переопределении методов

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

  • 1) Тип возвращаемого значения должен совпадать с типом возвращаемого значения родительского метода или удовлетворять условию ковариантности.

    Ковариантность позволяет дочернему методу возвращать более конкретный тип, чем в родительском методе (если тип возвращаемого значения родительского метода не указан, то дочерний метод может возвращать любой тип). В частности, если родительский метод возвращает объект, то допускается возвращение дочерним методом объекта производного класса. В следующем примере переопределенный метод new_patient класса LionClinic возвращает объект класса Lion вместо объекта класса Animal, возвращаемого родительским методом.

    <?php
    class Animal
    {
        protected $name;
    
        public function __construct($name)
        {
            $this->name = $name;
        }
    }
    
    class Lion extends Animal
    {
    }
    
    class VetClinic
    {
        public function new_patient($name): Animal
        {
            return new Animal($name);
        }
    }
    
    class LionClinic extends VetClinic
    {
        public function new_patient($name): Lion
        {
            return new Lion($name);
        }
    }
    
    
  • 2) Типы аргументов должны совпадать с типами соответствующих аргументов в родительском методе или удовлетворять условию контравариантности.

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

    <?php
    class VetClinic
    {
    }
    
    class CatClinic extends VetClinic
    {
    }
    
    class Cat
    {
        public function make_an_appointment(CatClinic $clinic)
        {
            //записываемся на прием
        }      
    }
    
    class BritishCat extends Cat
    {
        public function make_an_appointment(VetClinic $clinic)
        {
            //записываемся на прием
        }
    }
    
    
  • 3) Состав параметров дочернего метода должен быть таким же, как в родительском методе, или могут быть добавлены новые необязательные параметры (параметры по умолчанию).
  • 4) Обязательным параметрам родительского метода в дочернем могут быть присвоены значения по умолчанию.
mariyas's picture

дополнено "Совместимость при переопределении методов" п. 3) и 4)