This repository has been archived by the owner on Jun 2, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
late_static_bindings.php
executable file
·220 lines (165 loc) · 6.46 KB
/
late_static_bindings.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
<?php
/**
* late_static_bindings description
*
* @author Kudryashov Sergey iden.82@gmail.com
*/
/**
* Что понял - позднее статическое связывание позволяет узнать, какой класс вызвал
* данный метод. В случае статических вызовов это КЛАСС::Метод - левая часть, т.е.
* КЛАСС. В случае обычных вызовов это класс вызвавшего объекта.
* Кстати вызов с учетом SELF оставлен для обратной совместимости
* PHP
* Если кратко,
* новая функциональность позднего статического связывания, позволяет объектам
* все также наследовать методы у родительских классов, но помимо этого дает
* возможность унаследованным методам иметь доступ к статическим константам,
* методам и свойствам класса потомка, а не только родительского класса
* Новое ключевое слово static указывает,
* что необходимо использовать константу унаследованного класса,
* вместо константы которая была определена в классе где объявлен
* метод getStaticName(). Слово static было добавлено, чтобы реализовать
* новый функционал, а для обратной совместимости self работает также как и в
* предыдущих версиях PHP.
*
*
* Внутренне, основное отличие (и, собственно, причина почему связывание назвали поздним)
* между этими двумя способами доступа, в том, что PHP определят значение для self::NAME
* во время "компиляции" (когда симовлы PHP преобразуются в машинный код, который
* будет обрабатываться движком Zend), а для static::NAME значение будет определено
* в момент запуска (в тот момент, когда машинный код будет выполнятся в движке Zend).
*
*/
/**
* ПРимер с http://habrahabr.ru/blogs/php/23066/
*/
class Beer {
const NAME = 'Beer!';
public function getName() {
return self::NAME;
}
}
class Ale extends Beer {
const NAME = 'Ale!';
}
$beerDrink = new Beer;
$aleDrink = new Ale;
$test0 = $beerDrink->getName() ."\n"; // ВЫдаст Beer is: Beer!
$test1 = $aleDrink->getName() ."\n"; // Выдаст Ale is: Beer!
//Класс Ale унаследовал метод getName(), но при этом self все еще указывает на
//класс в котором оно используется (в данном случае это класс Beer).
//Это осталось и в PHP 5.3, но добавилось слово static. И снова рассмотрим пример:
class Beer2 {
const NAME = 'Beer!';
public function getName() {
return self::NAME;
}
public function getStaticName() {
return static::NAME;
}
}
class Ale2 extends Beer2 {
const NAME = 'Ale!';
}
$beerDrink = new Beer2;
$aleDrink = new Ale2;
$test2 = $beerDrink->getName() ."\n"; // Beer
$test3 = $aleDrink->getName() ."\n"; // Beer
$test4 = $beerDrink->getStaticName() ."\n"; // Beer
$test5 = $aleDrink->getStaticName() ."\n"; // Ale
/**
* Пример с php.net
*/
// вариант с self, когда статическое связывание НЕ отрабатывает
class A {
public static function who() {
return __CLASS__;
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
return __CLASS__;
}
}
$a = B::test(); // в этом случае, если бы рассматривался вариант с $this то вызван
// был бы метод B::who() а так - а.
$b = A::test();
echo $a;
/// Вариант, когда LSB отрабатывает
class A1 {
public static function who() {
return __CLASS__;
}
public static function test() {
return static::who(); // Here comes Late Static Bindings
}
}
class B1 extends A1 {
public static function who() {
return __CLASS__;
}
}
$r = B1::test(); // а вот здесь уже вызовется B1 - то есть как и в случае с $this
//In non-static contexts, the called class will be the class of the object instance.
//Since $this-> will try to call private methods from the same scope, using static::
//may give different results. Another difference is that static::
//can only refer to static properties.
// использование вне статического контекста
class A3 {
private function foo() {
echo "success!\n";
return __CLASS__;
}
public function test() {
$a1 = $this->foo();
$a2 = static::foo();
}
}
class B3 extends A3 {
/* foo() will be copied to B, hence its scope will still be A and
* the call be successful */
}
class C3 extends A3 {
private function foo() {
/* original method is replaced; the scope of the new one is C */
}
}
$b = new B3();
$b->test();
$c = new C3();
//$c->test(); //fails да здесь fatal
/*** контрольная проверка случая с $this***/
class abc
{
public function __construct() {
echo 'called abc construct';
}
function call()
{
return $this->test();
}
function test()
{
return __CLASS__;
}
}
class def extends abc
{
public function __construct() {
echo 'called def construct';
}
function test() {
return __CLASS__;
}
}
// вариант 1
$t = new abc();
$a = $t->call(); // в этом случае вызовется abc->test() и вернет abc
// вариант 2
$t= new def();
$a2 = $t->call(); // в этом случае вызовется def->test() и вернет def
/*** конец проверки ******/
?>