несколько способов вызова родительского метода в php

90

Сначала меня смутило, почему работают оба вызова методов в конструкторе, но теперь я думаю, что понимаю. Расширяющиеся классы наследуют родительские методы, как если бы они были объявлены в самом классе, И методы существуют в родительском, поэтому оба должны работать.

Теперь мне интересно, есть ли предпочтительный способ (т.е. лучшая практика) вызова метода (через parentили this), и действительно ли это идентичные способы выполнения одного и того же кода, или есть ли какие-либо предостережения при использовании одного вместо другой.

Извините, я, наверное, над этим подумал.

abstract class Animal {

    function get_species() {

        echo "test";

    }

}

class Dog extends Animal {

    function __construct(){

        $this->get_species();
        parent::get_species();

    }

}

$spike = new Dog;
Джерри
источник

Ответы:

120

Есть три сценария (которые я могу придумать), когда вы вызываете метод в подклассе, где метод выходит из родительского класса:

  1. Метод не перезаписывается подклассом, существует только в родительском классе.

    Это то же самое, что и ваш пример, и, как правило, лучше использовать. $this -> get_species(); Вы правы, что в этом случае они фактически одинаковы, но метод унаследован подклассом, поэтому нет причин для различения. Используя, $thisвы остаетесь последовательными между унаследованными и локально объявленными методами.

  2. Метод перезаписывается подклассом и имеет полностью уникальную логику от родителя.

    В этом случае вы, очевидно, захотите использовать, $this -> get_species();потому что вы не хотите, чтобы выполнялась родительская версия метода. Опять же, при постоянном использовании $thisвам не нужно беспокоиться о различии между этим случаем и первым.

  3. Метод расширяет родительский класс, добавляя к тому, что достигается родительским методом.

    В этом случае вы все равно хотите использовать `$this -> get_species();метод при вызове из других методов подкласса. Единственное место, где вы вызовете родительский метод, будет из метода, который перезаписывает родительский метод. Пример:

    abstract class Animal {
    
        function get_species() {
    
            echo "I am an animal.";
    
        }
    
     }
    
     class Dog extends Animal {
    
         function __construct(){
    
             $this->get_species();
         }
    
         function get_species(){
    
             parent::get_species();
             echo "More specifically, I am a dog.";
         }
    }
    

Единственный сценарий, который я могу представить, когда вам нужно было бы вызвать родительский метод непосредственно вне метода переопределения, был бы, если бы они выполняли две разные вещи, и вы знали, что вам нужна родительская версия метода, а не локальная. Этого не должно быть, но если бы он появился, чистый способ приблизиться к этому - создать новый метод с таким именем, как get_parentSpecies()где все, что он делает, это вызывает родительский метод:

function get_parentSpecies(){

     parent::get_species();
}

Опять же, это сохраняет все красиво и согласованно, позволяя вносить изменения / модификации в локальный метод, а не полагаться на родительский метод.

Энтони
источник
как бы я сделал это без "продления"? как будто у меня есть некоторая «нога» класса claass внутри класса «человек», но мне действительно не нужно ее расширять, поскольку мне не нужны родительские «человеческие» функции. теперь, если бы я создал $leg = new leg()внутри human, как бы мне вызвать человеческие функции из экземпляра ноги $leg?
user151496
@ user151496 Нога - это не подкласс человека. У человека много ног, но нога не принадлежит человеку. Следовательно, у вас не должно быть класса ноги, наследуемой от человека, потому что нога не человеческая.
Beetle
Вы бы сделали Leg классом с интерфейсом Leggy? Или просто реализовать Leggy в классе Human? Как мы можем лучше всего определить, что нога не является исключительной особенностью человека, но также что человеческие ноги являются исключительно человеческими и являются общим свойством людей?
Энтони
2
паамайим некудотаим немного сбивает с толку. На первый взгляд кажется, что вы вызываете статический метод. Вместо этого должно было быть parent-> get_species ()
peterchaula
Согласовано. Статические вызовы во многих отношениях очень сбивают с толку. Я должен обновить это в какой-то момент.
Энтони
5

Если я не неправильно понимаю вопрос, я бы почти всегда использовал $ this-> get_species, потому что подкласс (в данном случае dog) может перезаписать этот метод, поскольку он расширяет его. Если класс dog не переопределяет метод, тогда оба способа функционально эквивалентны, но если в какой-то момент в будущем вы решите, что хотите, чтобы метод get_species в dog должен был печатать «dog», тогда вам придется вернуться через весь код и Измени это.

Когда вы используете $ this, он фактически является частью созданного вами объекта и поэтому всегда будет также самым актуальным (если используемое свойство каким-то образом изменилось за время жизни объекта), тогда как при использовании родительского класса вызывает метод статического класса.

хакер
источник
это хороший момент для использования $ this на случай, если я хочу переопределить метод. Спасибо
Джерри