Когда использовать 'self' вместо '$this'?
В PHP 5 в чем разница между использованием self
и $this
?
Когда следует использовать каждый из них?
5 ответ(ов)
Краткий ответ
Используйте $this
для обращения к текущему объекту. Используйте self
для обращения к текущему классу. Другими словами, используйте $this->member
для нестатических членов, используйте self::$member
для статических членов.
Полный ответ
Вот пример правильного использования $this
и self
для нестатических и статических переменных-членов:
<?php
class X {
private $non_static_member = 1;
private static $static_member = 2;
function __construct() {
echo $this->non_static_member . ' '
. self::$static_member;
}
}
new X();
?>
Вот пример неправильного использования $this
и self
для нестатических и статических переменных-членов:
<?php
class X {
private $non_static_member = 1;
private static $static_member = 2;
function __construct() {
echo self::$non_static_member . ' '
. $this->static_member;
}
}
new X();
?>
Вот пример полиморфизма с использованием $this
для методов-членов:
<?php
class X {
function foo() {
echo 'X::foo()';
}
function bar() {
$this->foo();
}
}
class Y extends X {
function foo() {
echo 'Y::foo()';
}
}
$x = new Y();
$x->bar();
?>
Вот пример подавления полиморфного поведения с использованием self
для методов-членов:
<?php
class X {
function foo() {
echo 'X::foo()';
}
function bar() {
self::foo();
}
}
class Y extends X {
function foo() {
echo 'Y::foo()';
}
}
$x = new Y();
$x->bar();
?>
Идея заключается в том, что $this->foo()
вызывает метод foo()
того типа, который представляет текущий объект. Если объект имеет тип X
, то вызывается X::foo()
. Если объект имеет тип Y
, то вызывается Y::foo()
. Однако с self::foo()
всегда вызывается X::foo()
.
Ссылка на источник: http://www.phpbuilder.com/board/showthread.php?t=10354489
Автор: http://board.phpbuilder.com/member.php?145249-laserlight
В PHP self
(не $self
) ссылается на тип класса, тогда как $this
ссылается на текущий экземпляр класса. self
используется в статических методах для доступа к статическим переменным класса. $this
применяется в нестатических методах и представляет собой ссылку на экземпляр класса, на котором был вызван метод.
Так как this
является объектом, вы обращаетесь к его членам так: $this->member
.
Поскольку self
не является объектом, это, по сути, тип, который автоматически ссылается на текущий класс. Вы используете его следующим образом: self::member
.
$this->
используется для обращения к конкретному объекту класса, его переменным (членам класса) или методам.
$дerek = new Person();
Теперь $дerek
является конкретной экземпляром класса Person
. У каждого экземпляра Person
есть first_name
и last_name
, но у $derek
есть конкретные значения first_name
и last_name
(Дерек Мартин). Внутри экземпляра $derek
мы можем обращаться к этим переменным как $this->first_name
и $this->last_name
.
ClassName::
используется для обращения к самому классу и его статическим переменным и методам. Чтобы упростить восприятие, можно мысленно заменить слово "статический" на "разделяемый". Поскольку они разделяемые, они не могут обращаться к $this
, который ссылается на конкретный экземпляр (не разделяемый). Статические переменные (например, static $db_connection
) могут быть общими для всех экземпляров определенного типа объектов. Например, все объекты базы данных могут использовать одно соединение (статическую $connection
).
Пример статических переменных:
Предположим, у нас есть класс базы данных с одной член-переменной: static $num_connections;
. Теперь добавим это в конструктор:
function __construct()
{
if(!isset($num_connections) || $num_connections == null)
{
$num_connections = 0;
}
else
{
$num_connections++;
}
}
Так же, как объекты имеют конструкторы, они также имеют деструкторы, которые выполняются, когда объект уничтожается или снимается с учёта:
function __destruct()
{
$num_connections--;
}
Каждый раз, когда мы создаём новый экземпляр, это увеличивает наш счётчик соединений на единицу. Каждый раз, когда мы уничтожаем или перестаём использовать экземпляр, это уменьшает счётчик соединений на единицу. Таким образом, мы можем отслеживать количество экземпляров объекта базы данных, которые мы используем:
echo DB::num_connections;
Поскольку $num_connections
статическая (разделяемая), она будет отражать общее количество активных объектов базы данных. Вы могли видеть эту технику, используемую для разделения соединений с базой данных между всеми экземплярами класса базы данных. Это делается потому, что создание соединения с базой данных занимает много времени, поэтому лучше создать его один раз и использовать повторно (это называется паттерн «Одиночка»).
Статические методы (например, public static View::format_phone_number($digits)
) могут вызываться БЕЗ предварительного создания одного из этих объектов (они не ссылаются на $this
).
Пример статического метода:
public static function prettyName($first_name, $last_name)
{
echo ucfirst($first_name).' '.ucfirst($last_name);
}
echo Person::prettyName($derek->first_name, $derek->last_name);
Как видно, public static function prettyName
ничего не знает об объекте. Он просто работает с параметрами, которые вы передаете, как обычная функция, не относящаяся к объекту. Почему же тогда это нужно, если мы могли бы просто не делать из этого часть объекта?
- Во-первых, привязка функций к объектам помогает поддерживать порядок, так вы всегда будете знать, где их найти.
- Во-вторых, это предотвращает конфликты имен. В крупном проекте у вас, вероятно, будет два разработчика, создающих функции
getName()
. Если один создастClassName1::getName()
, а другой —ClassName2::getName()
, это не вызовет проблем. Нет конфликта. Ура статическим методам!
SELF::
Если вы пишете код вне объекта, к статическому методу которого вы хотите обратиться, вам нужно использовать имя объекта: View::format_phone_number($phone_number);
Если вы пишете код внутри объекта, который содержит статический метод, к которому вы хотите обратиться, вы можете использовать ЛИБО имя объекта: View::format_phone_number($pn)
, ЛИБО использовать сокращение self::format_phone_number($pn)
.
То же самое относится к статическим переменным:
Пример: View::templates_path
против self::templates_path
.
Внутри класса DB
, если мы хотим обратиться к статическому методу другого объекта, мы будем использовать имя этого объекта:
Пример: Session::getUsersOnline();
Но если класс DB
хочет обратиться к своей собственной статической переменной, он просто скажет self
:
Пример: self::connection;
В PHP ключевое слово self
используется для доступа к статическим свойствам и методам.
Проблема заключается в том, что вы можете заменить $this->method()
на self::method()
в любом месте, независимо от того, объявлен ли method()
как статический или нет. Так какой же из этих вариантов следует использовать?
Рассмотрим следующий код:
class ParentClass {
function test() {
self::who(); // выведет 'parent'
$this->who(); // выведет 'child'
}
function who() {
echo 'parent';
}
}
class ChildClass extends ParentClass {
function who() {
echo 'child';
}
}
$obj = new ChildClass();
$obj->test();
В этом примере self::who()
всегда будет выводить «parent», в то время как $this->who()
будет зависеть от того, в каком классе находится объект.
Таким образом, мы можем увидеть, что self
ссылается на класс, в котором оно было вызвано, тогда как $this
ссылается на класс текущего объекта.
Поэтому следует использовать self
только тогда, когда $this
недоступен или когда вы не хотите позволить дочерним классам переопределить текущий метод.
self
ссылается на текущий класс (в котором он вызывается), в то время как $this
ссылается на текущий объект. Вместо self
можно использовать static
.
Вот пример:
class ParentClass {
function test() {
self::which(); // Выведет 'parent'
$this->which(); // Выведет 'child'
}
function which() {
echo 'parent';
}
}
class ChildClass extends ParentClass {
function which() {
echo 'child';
}
}
$obj = new ChildClass();
$obj->test();
Вывод:
parent
child
Таким образом, self
всегда будет ссылаться на метод класса, в котором он определен (в данном случае ParentClass
), тогда как $this
указывает на экземпляр объекта, в котором метод вызывается (в данном случае объект ChildClass
).
Понимание Python super() с методами __init__()
Почему классы в Python наследуют от object?
Разница между public, private и protected в ООП
Разница между старыми и новыми классами в Python?
Функции startsWith() и endsWith() в PHP