Подтвердить что ты не робот

Вызов нестатического метода с двойной колонкой (::)

Почему я не могу использовать метод нестатический с синтаксисом методов static (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
4b9b3361

Ответ 1

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

На самом деле это ошибка, если у вас строгая отчетность об ошибках, но не иначе.

Ответ 2

Это известная "причуда" 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
?>

Ответ 3

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

Ответ 4

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

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

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

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

и/или

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

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

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

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

Ответ 5

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

Ответ 6

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

Ссылка

Ответ 7

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

Ответ 8

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

Что-то простое:

<?php
class Foo {

    private $color;

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

Foo::bar();

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

Ответ 9

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