викликати статичний метод всередині класу?


166

як мені викликати статичний метод з іншого методу всередині того ж класу?

$this->staticMethod();

або

$this::staticMethod();

13
Вас це може зацікавити ( selfпорівняно $this): stackoverflow.com/questions/151969/php-self-vs-this
Фелікс Клінг

Лише FYI, ваш перший приклад - це змінна інстанція, що викликає статичний метод, що неможливо, оскільки статичний метод є частиною класу і недоступний через змінну екземпляра.
joejoeson

ви можете видалити $ this now, будь ласка, він не працює, якщо використовуватись лише статичні методи, і жоден екземпляр не існує.
маль

Відповіді:


321

...але чому? $ this-> staticMethod () також працює. Чи можете ви пояснити, чому self :: staticMethod () правильніше (якщо воно є)?
Ян Данн

29
@Ian Dunn Put просто, $thisіснує лише в тому випадку, якщо об'єкт був інстанційним, і ви можете використовувати його лише $this->methodз існуючого об'єкта. Якщо у вас немає об'єкта, а просто виклик статичного методу, і в цьому методі ви хочете викликати інший статичний метод того ж класу, ви повинні використовувати self::. Тому, щоб уникнути можливих помилок (і суворих попереджень), краще використовувати self.
jeroen

1
Дякую! У laravel я виявив, що я випадково викликав статичний метод через розширений контролер за допомогою $this, але проблема не поверталася до тих пір, поки код не був висунутий stage. жодних помилок не повернулося, значення було справедливим 0. будьте обережні з цим, використовуйтеself::
blamb

44

Припустимо, це ваш клас:

class Test
{
    private $baz = 1;

    public function foo() { ... }

    public function bar() 
    {
        printf("baz = %d\n", $this->baz);
    }

    public static function staticMethod() { echo "static method\n"; }
}

Зсередини foo()методу розглянемо різні варіанти:

$this->staticMethod();

Так що виклики staticMethod()як метод екземпляра, правда? Це не. Це тому, що метод оголошується так, public staticяк інтерпретатор буде називати його статичним методом, тому він буде працювати, як очікувалося. Можна стверджувати, що це робить менш очевидним з коду, що відбувається виклик статичного методу.

$this::staticMethod();

Оскільки PHP 5.3 ви можете використовувати $var::method()для значення <class-of-$var>::; це досить зручно, хоча вищевказаний випадок використання все ще є досить нетрадиційним. Отже, це підводить нас до найпоширенішого способу виклику статичного методу:

self::staticMethod();

Тепер, перш ніж ви починаєте думати , що ::це оператор статичного виклику, дозвольте мені дати вам ще один приклад:

self::bar();

Це буде друкувати baz = 1, це означає , що $this->bar()і self::bar()робити те ж саме; це тому, що ::це лише оператор роздільної здатності. Це там , щоб зробити parent::, self::і static::роботу , і ви отримаєте доступ до статичних змінних; як називається метод, залежить від його підпису та того, як викликався абонент.

Щоб побачити все це в дії, дивіться цей вихід 3v4l.org .


self::bar()здається оманливим - це тепер застаріле? (використовується self::для виклику методу екземпляра, а не статичного методу).
ToolmakerSteve

@ToolmakerSteve Яким чином ви б сказали, що це вводить в оману?
Ja͢ck

Логічно кажучи, немає selfпри використанні статичного методу. За визначенням: статичний метод можна дзвонити з будь-якого місця та не отримує параметр "self". Тим не менш, я бачу зручність цього phpсинтаксису, так що вам не доведеться писати MyClassName::. Я звик до мов статичного типу, де компілятору слід надати всі змінні, доступні в поточній області, тому (еквівалент) self::можна опустити. Так один сказав лише self instanceMethod; немає підстав сказати self staticMethod.
ToolmakerSteve

15

Це дуже пізня відповідь, але додає деяку детальність попередніх відповідей

Що стосується виклику статичних методів у PHP від ​​іншого статичного методу того ж класу, важливо розмежовувати selfназву класу.

Візьмемо для прикладу цей код:

class static_test_class {
    public static function test() {
        echo "Original class\n";
    }

    public static function run($use_self) {
        if($use_self) {
            self::test();
        } else {
            $class = get_called_class();
            $class::test(); 
        }
    }
}

class extended_static_test_class extends static_test_class {
    public static function test() {
        echo "Extended class\n";
    }
}

extended_static_test_class::run(true);
extended_static_test_class::run(false);

Вихід цього коду:

Оригінальний клас

Розширений клас

Це пояснюється тим, що selfвідноситься до класу, в якому знаходиться код, а не до класу коду, з якого він викликається.

Якщо ви хочете використовувати метод, визначений для класу, який успадковує вихідний клас, вам потрібно використовувати щось на кшталт:

$class = get_called_class();
$class::function_name(); 

2
Я знайшов це інформативним. Невелика нітка, я б не сказав, що інші відповіді "оманливі". Точніше сказати, що вони "неповні"; вони не звертаються до (не заданого) питання про те, що self::робиться в (рідкісному) випадку, коли статичний метод A викликає інший статичний метод B, а B підменено в підкласі. IMHO, менш заплутано обмежувати метод, що переосмислює методи "екземпляр"; використовувати цю здатність економно на статичному рівні. По-іншому, читачі вашого коду очікують, що метод переопределення методів екземплярів (це суть кодування OO), але не статичних.
ToolmakerSteve

1
Дуже корисно і має сенс, що розширення класу не є початковим класом. Тому, selfочевидно, це не було б використано в такому випадку. Ви оголосили окремий клас як розширення до першого класу. Використання selfв розширеному класі означатиме розширений клас. Це не суперечить іншим відповідям, але, безумовно, допомагає продемонструвати сферу застосування self.
iyrin

2

У пізнішій версії PHP self::staticMethod();також не буде працювати. Це викине сувору стандартну помилку.

У цьому випадку ми можемо створити об'єкт одного класу та викликати за об'єктом

ось приклад

class Foo {

    public function fun1() {
        echo 'non-static';   
    }

    public static function fun2() {
        echo (new self)->fun1();
    }
}

Ви можете це зробити, хоча якщо fun1не використовуєте self, не логічно зробити його методом екземпляра. Правильний спосіб зробити це в PHP, щоб оголосити public static function fun1, а потім викликати, вказавши клас: Foo::fun1. Я впевнений, що це призначений спосіб виправити цю сувору стандартну помилку.
ToolmakerSteve
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.