Вызов нестатического метода с двойным двоеточием (: :) - PullRequest
46 голосов
/ 20 сентября 2010

Почему я не могу использовать нестатический метод с синтаксисом статических методов (class :: method)?Это какая-то проблема конфигурации?

class Teste {

    public function fun1() {
        echo 'fun1';
    }
    public static function fun2() {
        echo "static fun2" ;
    }
}

Teste::fun1(); // why?
Teste::fun2(); //ok - is a static method

Ответы [ 9 ]

32 голосов
/ 21 сентября 2010

PHP очень слаб в использовании статических и нестатических методов.Одна вещь, которую я здесь не заметил, это то, что если вы вызываете нестатический метод, ns статически из нестатического метода класса C, $this внутри ns будет ссылаться на ваш экземплярC.

class A 
{
    public function test()
    {
        echo $this->name;
    }
}

class C 
{
     public function q()
     {
         $this->name = 'hello';
         A::test();
     }
}

$c = new C;
$c->q();// prints hello

Это действительно какая-то ошибка, если у вас есть строгие сообщения об ошибках, но не иначе.

25 голосов
/ 20 сентября 2010

Это известная «причуда» PHP.Это сделано для предотвращения обратного распространения, чтобы выяснить, действительно ли мы когда-то создавали объект или нет (помните, что PHP интерпретируется, а не компилируется).Однако доступ к любому нестатическому члену через оператор разрешения области действия, если объект не был создан, вызовет фатальную ошибку.

Предоставлено PHP.net:

class User {
    const GIVEN = 1;  // class constants can't be labeled static nor assigned visibility
    public $a=2;
    public static $b=3;

    public function me(){
        echo "print me";
    }
     public static function you() {
        echo "print you";
    }
}

class myUser extends User {
}

// Are properties and methods instantiated to an object of a class, & are they accessible?
//$object1= new User();        // uncomment this line with each of the following lines individually
//echo $object1->GIVEN . "</br>";        // yields nothing
//echo $object1->GIVE . "</br>";        //  deliberately misnamed, still yields nothing
//echo $object1->User::GIVEN . "</br>";    // yields nothing
//echo $object1->a . "</br>";        // yields 2
//echo $object1->b . "</br>";        // yields nothing
//echo $object1->me() . "</br>";        // yields print me
//echo $object1->you() . "</br>";        // yields print you

// Are  properties and methods instantiated to an object of a child class,  & are accessible?
//$object2= new myUser();        // uncomment this line with each of the following lines individually
//echo $object2->GIVEN . "</br>";        // yields nothing
//echo $object2->a . "</br>";        // yields 2
//echo $object2->b . "</br>";        // yields nothing
//echo $object2->me() . "</br>";        // yields print me
//echo $object2->you() . "</br>";        // yields print you

// Are the properties and methods accessible directly in the class?
//echo User::GIVEN . "</br>";        // yields 1
//echo User::$a . "</br>";            // yields fatal error since it is not static
//echo User::$b . "</br>";            // yields 3
//echo User::me() . "</br>";        // yields print me
//echo User::you() . "</br>";        // yields print you

// Are the properties and methods copied to the child class and are they accessible?
//echo myUser::GIVEN . "</br>";        // yields 1
//echo myUser::$a . "</br>";        // yields fatal error since it is not static
//echo myUser::$b . "</br>";        // yields 3
//echo myUser::me() . "</br>";        // yields print me
//echo myUser::you() . "</br>";        // yields print you
?>
15 голосов
/ 09 сентября 2013

Это PHP 4 обратная совместимость.В PHP 4 вы не могли различать метод объекта и глобальную функцию, написанную как метод статического класса.Следовательно, оба сработали.

Однако с изменениями в объектной модели с PHP 5 - http://php.net/oop5 - было введено ключевое слово static.

А затем, начиная с PHP 5.1.3вы получите правильные строгие стандартные предупреждения о таких как:

Строгие стандарты: Нестатический метод Foo :: bar () не должен вызываться статически

И / или:

Строгие стандарты: Нестатический метод Foo :: bar () не следует вызывать статически, предполагая $ this из несовместимого контекста

, который вы должны включить для своегонастройка разработки.Так что это просто обратная совместимость со временем, когда язык не мог достаточно различаться, поэтому он был «определен» во время выполнения.

В настоящее время вы можете определить его уже в коде, однако код не будет нарушаться, еслиВы все еще называете это "неправильно".

Некоторая демонстрация для запуска сообщений об ошибках и отображения измененного поведения в разных версиях PHP: http://3v4l.org/8WRQH

13 голосов
/ 20 сентября 2010

В PHP 4 не было статического ключевого слова (в контексте объявления функции), но все же разрешалось вызывать методы статически с ::. Это продолжалось в PHP 5 для целей обратной совместимости.

6 голосов
/ 27 октября 2017

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

Ссылка

6 голосов
/ 20 сентября 2010

Вы можете сделать это, но ваш код выдаст ошибку, если вы используете $this в функции с именем fun1()

1 голос
/ 20 сентября 2010

Не уверен, почему PHP позволяет это, но вы не хотите привыкать делать это. Ваш пример работает только потому, что он не пытается получить доступ к нестатическим свойствам класса.

Что-то простое, как:

<?php
class Foo {

    private $color;

    public function bar() {
        echo 'before';
        $this->color = "blue";
        echo 'after';
    }
}

Foo::bar();

приведет к фатальной ошибке

1 голос
/ 20 сентября 2010

В большинстве языков вам понадобится экземпляр класса для выполнения методов экземпляра. Похоже, что PHP создаст временный экземпляр при вызове метода экземпляра с оператором разрешения области действия.

0 голосов
/ 22 февраля 2014

Я заметил, что если вы вызываете нестатический метод self :: test () из класса, предупреждение о строгом стандарте не выдается, как при вызове Class :: test ().Я считаю, что это не связано с LSB, так как мой класс не был расширен (проверено на php 5.5)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...