Экземпляр против статического метода. Называя это статически или динамически

В PHP есть методы экземпляра и статические методы (только эти два типа)? Тогда мы можем назвать любой из них статически или нестатически (имя «динамически»?)?

Так что мы можем:

  1. Вызовите метод экземпляра статически;
  2. Вызовите метод экземпляра нестатически;
  3. Вызов статического метода статически;
  4. Вызвать статический метод нестатически (все четыре правильные?)

Как будет выглядеть код для этих четырех? Есть ли хорошие сайты, объясняющие это? В настоящее время я читаю следующий URL:

http://php.net/manual/en/language.oop5.basic.php

…и я не понимаю этого

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

Как будет выглядеть код для статического вызова метода из вторичного объекта? Я имею в виду, статический вызов против нестатического вызова, что это?

1

Решение

Вы не должны вызывать нестатические методы статически.

Некоторые примеры

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__;
}
}

Несколько других вещей, на которые следует обратить внимание

  • При вызове static $ this не используется, предполагается, что вы будете использовать $ this в нестатическом методе, поэтому статический вызов может вызвать проблему.
  • При вызове нестатического $ это существует, и нет никаких проблем с выполнением статического вызова, поэтому не статический вызов статических методов не является проблемой. то есть. self и static доступны вне зависимости от контекста.
  • Статические свойства являются общими для всех экземпляров класса
  • Статические свойства, доступные в parent, не могут быть изменены детьми (при использовании self)
  • Статические свойства, доступные в parent, могут быть изменены дочерними элементами (при использовании статической поздней статической привязки)

Теперь, если вы хотите точные ответы:

  1. Вызовите метод экземпляра статически;
    • вы можете, но не должны, потому что $ this не существует
  2. Вызовите метод экземпляра нестатически;
    • это нормально
  3. Вызов статического метода статически;
    • это тоже нормально
  4. Вызвать статический метод нестатически (все четыре правильные?)
    • уверен, что статические доступны независимо от объема

Мы можем показать это на примере, используя приведенный выше класс

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 ‘true’
  • значение бара равно false

Для первого мы получаем значение 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();

Я уверен, что есть и другие причины, но это главные для меня.

1

Другие решения

Давайте посмотрим следующий код:

<?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

Это «работает», но вы не должны вызывать нестатические методы из статического контекста.

0

По вопросам рекламы [email protected]