В PHP есть методы экземпляра и статические методы (только эти два типа)? Тогда мы можем назвать любой из них статически или нестатически (имя «динамически»?)?
Так что мы можем:
Как будет выглядеть код для этих четырех? Есть ли хорошие сайты, объясняющие это? В настоящее время я читаю следующий URL:
http://php.net/manual/en/language.oop5.basic.php
…и я не понимаю этого
«$ это ссылка на вызывающий объект (обычно это объект, которому принадлежит метод, но, возможно, другой объект, если метод вызывается статически из контекста вторичного объекта)».
Как будет выглядеть код для статического вызова метода из вторичного объекта? Я имею в виду, статический вызов против нестатического вызова, что это?
Вы не должны вызывать нестатические методы статически.
Некоторые примеры
class foo{
public static function bar(){
echo __METHOD__;
}
public function biz(){
echo __METHOD__;
}
}
тесты
//instance call
(new foo)->biz(); //echos foo::biz (don't worry about the :: here, its part of __METHOD__)
//static call, statically
foo::bar() // echos foo::bar
//call non-static statically
foo::biz() //in PHP7.1
<b>Deprecated</b>: Non-static method foo::biz() should not be called statically in <b>[...][...]</b> on line <b>18</b><br />
//call static non-statically
(new foo)->bar(); // echos foo::bar
Идея вызова статического нестатически заключается в том, что допустимо использовать статические свойства внутри нестатических методов. Например:
class foo{
protected static $boo = "hello";
public static function bar(){
echo __METHOD__;
}
public function biz(){
echo __METHOD__;
echo self::$boo;
echo static::$boo; //late static binding
}
}
Так что это нормально, теперь оборотная сторона вызывает нестатические методы внутри статических методов.
class foo{
protected $boo = "hello";
public static function bar(){
echo __METHOD__;
$this->boo; // this is a no no, because no instance exists and therefor $this does not work
}
public function biz(){
echo __METHOD__;
}
}
Несколько других вещей, на которые следует обратить внимание
Теперь, если вы хотите точные ответы:
Мы можем показать это на примере, используя приведенный выше класс
class foo{
public static function bar(){
echo __METHOD__;
}
public function biz(){
echo __METHOD__;
print_r($this);
}
}
//call non-static statically
foo::biz();
Результат (PHP7 +)
<br />
<b>Deprecated</b>: Non-static method foo::biz() should not be called statically in <b>[...][...]</b> on line <b>15</b><br />
foo::biz //output of __METHOD__
<br />
<b>Fatal error</b>: Uncaught Error: Using $this when not in object context in [...][...]:11
Stack trace:
#0 [...][...](15): foo::biz()
#1 {main}
thrown in <b>[...][...]</b> on line <b>11</b><br />
Как вы видите, мы получаем фатальную ошибку при попытке доступа $this
Результат (PHP5 что-то)
<br />
<b>Strict Standards</b>: Non-static method foo::biz() should not be called statically in <b>[...][...]</b> on line <b>16</b><br />
foo::biz<br />
<b>Notice</b>: Undefined variable: this in <b>[...][...]</b> on line <b>11</b><br />
Теперь мы не получаем фатальную ошибку в PR PHP7 (что-то), и на первый взгляд это может показаться нормальным. Как и его поговорка, так хорошо бежать. Однако если вы посмотрите ближе Undefined variable: this
это на самом деле хуже, чем фатальная ошибка, потому что теперь ваш класс может давать неожиданные результаты.
Если бы мы назвали это нормальным:
(new foo)->biz();
Результат
foo::biz //output of __METHOD__
foo Object //output of $this
(
)
Поэтому я хочу дать вам один быстрый пример self
против static
, это может быть действительно запутанным.
class foo{
protected static $test = 'true';
public function boo(){
echo self::$test."\n";
echo static::$test."\n";
}
}
class bar extends foo{
protected static $test = 'false';
public function biz(){
echo self::$test."\n";
echo static::$test."\n";
}
}
$B = new bar;
$B->boo();
echo "--------------\n";
$B->biz();
Результат
-------------- defined in parent ----
true //call boo() self
false //call boo() static
-------------- defined in child ----
false //call biz() self
false //call biz() static
Когда вы используете static
это называется поздним статическим связыванием. Это означает, что статическое значение связано поздно. Так что же на самом деле это значит? Это означает, что значение разрешается во время выполнения, а не тогда, когда класс анализируется PHP.
bar
это ребенок foo
, foo
, все наши звонки проходят foo
, boo
существует только у родителя, т.е. он не перезаписывается дочерним методом.Для первого мы получаем значение foo
потому что мы используем себя, поэтому он знает только о себе.
Для второго мы получаем значение bar
потому что мы используем static, он привязан поздно и может использовать значение потомка, которое установлено в его объявлении свойства $test
, Таким образом, хотя родитель не знает ничего о дочернем элементе (типично), он может использовать его значение, поскольку он разрешается во время выполнения.
для третьего мы получаем значение bar
потому что он знает о себе, а метод определяется сам по себе. foo
ничего не знает об этом методе, даже если бы он делал это, он был бы перезаписан замедлением его у ребенка.
для четвертого снова получаем значение bar
это потому, что даже при позднем статическом связывании мы извлекаем те же данные, значение bar
так как bar
это класс, который мы создали, поэтому во время выполнения значение, определенное в свойстве, является значением.
Таким образом, в последних 2 значение одно и то же, потому что self и static разрешают одну и ту же информацию независимо от того, когда они вызываются.
Это может быть очень запутанным, так что, надеюсь, это имеет смысл. Также, как я показал, не бойтесь создавать такие простые классы и проверять полученные значения. Вот как я узнал.
Вы упомянули, что использование статических вызовов было сочтено плохим.
Я думаю, что большая часть этого связана с проблемами зависимости. Это тесная связь между названием класса и вашим кодом. При использовании экземпляра вы присваиваете его переменной и используете имя 1 раз при вызове new. При вызове static вы используете имя класса каждый раз. Проблема, которая вызывает это, если вы решите переименовать класс. При вызове экземпляра вам нужно всего лишь заменить имя, где вы вызываете новое, статическим, вы должны заменить его везде.
Например, рассмотрим это.
$foo = new foo;
$foo->one();
$foo->two();
//say you inject this into another class
$foo->three();
И сравните это с этим.
foo::one();
foo::two();
//say you inject this into another class
foo::three();
Теперь скажите, что вы изменили имя класса. Для первого вы должны заменить его в одном месте. Для второго вы должны заменить его каждый раз, когда вы его использовали. Вы можете обойти это несколько используя строковую переменную.
$class = 'foo';
$class::one();
$class::two();
//say you inject this into another class
$class::three();
Но с этим вы тоже можете столкнуться с большими проблемами, потому что большинство IDE не смогут разрешить класс и выполнить автозаполнение.
Также, если вы делаете намеки на ввод для других классов
class other{
public method inject(foo $foo){}
}
Это не очень хорошо работает со статическими классами, потому что тогда вы передаете строку (имя класса).
Пространства имен могут быть проблемой. В случае создания экземпляра вам нужно всего лишь поместить оператор использования в файл, в котором вы создаете экземпляр класса. В случае со static вы должны помещать его везде или включать в каждый вызов.
\mystuff\foo::bar();
$foo = '\\mystuff\\foo';
$foo::bar();
Я уверен, что есть и другие причины, но это главные для меня.
Давайте посмотрим следующий код:
<?php
class A
{
public $property = "property A";
public function testA()
{
echo "class A ";
echo $this->property;
}
}
class B
{
public $property = "property B";
public function testB()
{
A::testA();
}
}
$b = new B;
$b->testB();
Будет отображаться class A property B
Вы получаете доступ к недвижимости из B
, в A
класс, с $this
,
Это не будет работать на PHP 7+, и вы получите следующее предупреждение на PHP 5.6:
WARNING Non-static method A::testA() should not be called statically, assuming $this from incompatible context on line number 16
Это «работает», но вы не должны вызывать нестатические методы из статического контекста.