Вызов нестатического метода с двойной колонкой (::)
Почему я не могу использовать метод нестатический с синтаксисом методов 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
Ответы
Ответ 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)?