-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathPHP.htm
499 lines (399 loc) · 24.7 KB
/
PHP.htm
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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="" />
<meta name="author" content="Maxim Sokhatsky" />
<title>2020-12-31</title>
<link rel="stylesheet" href="https://n2o.dev/blank.css" />
<link rel="stylesheet" href="https://tonpa.guru/journal.css" />
</head>
<body>
<nav>
<a href='index.html'>Languages</a>
<a href='#'>PHP</a>
</nav>
<main>
<section>
<h3>PHP</h3>
<P>В твіттері Сохацькому не дають працювати і знову відтягують на графоманство.
За допомогою капіталістичного шантажу мене змусили написати статтю для
нашої Енциклопедії мов програмування. А саме стаття про мову програмування PHP,
на якій написане все зло людства --- Фейсбук, і навіть пара популярних сайтів
типу Вікіпедії та продуктів типу Вордпрес і Ларавель.</p>
<p>Я рідко даю розширені ретроспективи мовам, тому що вважаю це журналістикою,
вона може бути хорошою чи поганою, але вона не замінить самого письма.
Тому мені абсолютно байдуже, яку спадщину має ця мова, на скількох
пристроях вона працює, скільки грошей, реклами, котів чи порно ці
мови обробляють за наносекунди. Для мене це другорядні речі,
тому що модулі написані на найкрасивіших мовах програмування,
і вони взагалі ніде не використовуються. Так, що все це
починаючи з якогось момента дуже відносно.</p>
<p>З іншого боку, смішно писати про PHP коротко (із зазначенням лише
нотації BNF, семантики, історичної довідки та тактико-технічних
характеристик) — ця мова заслуговує на історію раннього вебу
та швидко закріплені унікальні шляхи розвитку. що визначило web 2020.
Сучасна мережа 2020 — це як Коронавірус — інфекція, яка випадково
вбиває навіть найсміливіших і запечатує їх у забуття. Потрібно
розуміти, що PHP створювався в той час, коли Netscape домінував
у мережі, про що ви можете знайти фільми в Нешинал Джеографік.
У той час JavaScript був невеликим механізмом скриптів, створеним
для анімації падаючих новорічних сніговиків на веб-сторінках (тоді це було модно),
і ця технологія називалася DHTML.</p>
<p>Тут я хотів би відпустити думки і пояснити, чому ми ненавидимо капіталізм,
гроші і технології, які під їхнім тиском застигають і набувають інерції
граничної швидкості руху. Трьома вершниками цього апокаліпсису
є Netscape, JavaScript і PHP. Хоча ці речі певною мірою повністю
доповнюють одна одну і нагадують мені зараз щось на кшталт повного
стосу архаїчних систем, а не сучасних засобів розробки. Якщо ми
скажемо зараз, завдання полягатиме в тому, щоб написати новий
стандарт для всього, починаючи з віртуальної машини, синтаксису
та мови — я думаю, кожен погодиться на щось більш освічене та культурне.
Тепер ці речі виглядають для освічених людей так само,
як ALGOL і PL/1 виглядають для нас зараз, мови навіть
більш архаїчні та не менш легендарні.</p>
<p>Концепція веб-сайту проста, як чиста лямбда: у контекстно-незалежному
середовищі шаблон видає нову сторінку за кожним запитом і вмирає.
Крім того, спеціалізований клієнт (браузер) виконує JavaScript
для запиту нових сторінок, перемальовуючи частини сторінки без
перезавантаження (так, DHTML або те, що зараз називається SPA,
було доступне навіть за часів Netscape). У зв'язку з цим все ідеально:
контекстно-незалежний шаблон PHP (який можна зробити контекстно-залежним,
підключивши базу), спеціалізований клієнт, віртуальна машина для написання
сторінок. Будь-який архітектор, який збирався рефакторити сучасну мережу,
залишив би цю трійку. Та й усі спроби переписати веб так чи інакше
зводяться до цих компонентів.</p>
<p>Однак розвиток мов і середовища виконання зайшов далеко, і багатьох
проблем існуючої мережі можна було б уникнути, маючи хоча б найменшу
можливість щось змінити, але змінити нічого неможливо, можна лише
спробувати почекати. На жаль, сучасна мережа інфікована цією трійкою.</p>
<p>Кожен із компонентів (як віруси) природно намагався замінити сам себе.
Так JavaScript хотів замінити Dart найзліснішою корпорацією на планеті,
хоча поруч завжди була Lua, яка також чудово підходила на роль
JIT-інтерпретатора. Тут OpenResty для NGNIX вже виглядає кращим
стеком, ніж LAMP! У ньому хоча б по одному компоненту все покращено,
латентність зменшена за рахунок JIT-запуску прямо в веб-сервері,
загалом справжнє (тільки слабкі стеки).</p>
<p>Іншим прикладом хорошої заміни є заміна PHP перетворенням XSLT.
Також послідовний і абсолютно інший підхід до відтворення
клієнтського вмісту. У цьому підході дані між клієнтом запускаються
виключно на типі XSD, самі запити виконуються через SOAP, XSLT
кешується в браузері (так, браузер може це робити), а сама
сторінка відображається на клієнті. Результатом є чистий
бекенд XML-RPC, усе стандартизоване та кероване. Я бачив
деякі частини ПриватБанку, побудовані на цій технології
в 2011 році, шкода, що тема з XSLT в браузері не стала
загальнопопулярною, багато в чому через синхронність
перетворень (потрібен повний набір даних), але я думаю,
що можна було б розширити деякі стандартні потоки або
навіть Pi-числення, якщо це потрібно. Не було сильної руки ринку,
яка харчувалася необхідним продуктом.</p>
<p>Але були й погані приклади наслідування. Інші мови негайно скопіювали успіх PHP.
Так JSP з’явився у світі Java, ASP у світі Microsoft, DTL у світі Python тощо.
тощо сотні з них, і всі беруть свій початок від Netscape/JavaScript/PHP.
JavaScript був і залишається основним веб-браузером без видимої можливості
бути заміненим у найближчому майбутньому. Хіба що йому вдалося заразити
серверні бекенди: на придуманій для сніжинок мові компанія Joyent
запропонувала писати серверні мережеві додатки.</p>
<p>Тож давайте почнемо класифікувати екстремуми підходу до відтворення
вмісту: 1) на клієнті (XSLT), чисті дані по дроту? 2) на сервері (PHP),
html-over-http. Знову ж таки, існують тисячі фреймворків, які реалізують
ці два підходи, і в мовах, які існували до PHP, таких як Perl або Python.
Насправді в ті часи це називалося CGI. Будь-яка програма, розміщена в
контексті веб-сервера, ставала шаблоном, наприклад, написана на Pascal,
тоді веб не був прив’язаний до мови. Одночасно з PHP з'явилася не менш
легендарна і більш послідовна мова програмування Ruby з розвиненою
системою макросів, так необхідних у веб-програмуванні, синтаксис
яких був перенесений на інші віртуальні машини та платформи.
До речі про них.</p>
<p>У світі кодової бази Facebook, яка швидко розвивається,
будь-яка корпорація була змушена захистити свої інвестиції
та написати власну віртуальну машину та власну мову з
визначенням типу (і тип одиниці, який негайно знижується
до нетипової лямбда). Facebook успішно працює на HipHop VM,
яка створена більш технологічно, ніж оригінальний PHP. Мова
також була вдосконалена та усереднена до спільного знаменника
всіх ООП-мов із дженериками. Нажаль це не втримало HVVM від End of Life.</p>
<p>Особливістю побудови PHP-систем є перенесення кеш-пам'яті
в спеціальне сховище (наприклад, Redis або Erlang) для
зберігання даних сесії (а також баз даних) для мінімізації
контексту рендерингу контейнерів і оптимізації розподілу
пам'яті в інтерпретаторі. Інший підхід полягає в об'єднанні
обчислювальної пам’яті з контекстом веб-сервера та створенні
довготривалих контейнерів додатків в однорідному мовному
середовищі з високою локальністю даних (зниження трафіку,
вартість) аж до інтеграції з шиною та системою зберігання
даних. Це друга (більш монолітна версія), яка замінює
старий підхід швидкого припинення всього процесу після
відтворення сторінки. Інші проблеми в пайплані PHP полягають в неможливості
побудови принципово ідіоматичного довгограючого WebSocket
сервера (без чого сучасний веб немислимий). Були спроби
типу phpDaemon і FastCGI, але це вже не справжній PHP і
працює гірше конкурентів.</p>
<p>Єдиний вихід для PHP-бізнесу — це просто запускати проекти,
поки є ринок, підтримуючи людей, які працюють виключно в
Інтернеті: веб-магазини, саморобні ERP-системи, системи
керування контентом. Це як COBOL, стільки написано, що
працюватиме ще 50 років. Чи варто новому програмісту
починати вивчати PHP? Хіба що з археологічної точки
зору, оскільки мова не складна, і вам потрібно зрозуміти
її нішу, щоб вважатися професіоналом у веб-програмуванні.
Якщо вже є якийсь проект на PHP, наприклад, написана
власна система управління підприємством, то є сенс
оновити його до HHVM, а там напевно до вас прийдуть
і запропонують переписати його в щось. Прислухайтеся
до них, це окупиться, але не викидайте і версію PHP.</p>
<h3>БНФ-нотаці</h3>
<p>Наводжу БНФ-нотацію приблизно тої версії мови,
на якій я писав на першій своїй роботі.</p>
<figure><code style="font-size:8pt;">
PHP_SOURCE_TEXT = { inner_statement | halt_compiler_statement };
halt_compiler_statement = "__halt_compiler" "(" ")" ";" ;
inner_statement = statement
| function_declaration_statement
| class_declaration_statement ;
inner_statement_list = { inner_statement } ;
statement = "{" inner_statement_list "}"
| "if" "(" expr ")" statement {elseif_branch} [else_single]
| "if" "(" expr ")" ":" inner_statement_list {new_elseif_branch}
[new_else_single] "endif" ";"
| "while" "(" expr ")" while_statement
| "do" statement "while" "(" expr ")" ";"
| "for" "(" for_expr ";" for_expr ";" for_expr ")" for_statement
| "switch" "(" expr ")" switch_case_list
| "break" [expr] ";"
| "continue" [expr] ";"
| "return" [expr_without_variable | variable] ";"
| "global" global_var {"," global_var} ";"
| "static" static_var { "," static_var } ";"
| "echo" echo_expr_list ";"
| T_INLINE_HTML
| expr ";"
| "use" use_filename ";" # FIXME: not implemented
| "unset" "(" variable {"," variable} ")" ";"
| "foreach" "(" (variable|expr_without_variable)
"as" foreach_variable ["=>" foreach_variable] ")"
foreach_statement
| "declare" "(" declare_list ")" declare_statement
| ";" # empty statement
| "try" "{" inner_statement_list "}" catch_branch {catch_branch}
| "throw" expr ";" ;
catch_branch = "catch" "(" fully_qualified_class_name T_VARIABLE ")" "{"
inner_statement_list "}" ;
use_filename = T_CONSTANT_ENCAPSED_STRING
| "(" T_CONSTANT_ENCAPSED_STRING ")" ;
function_declaration_statement = "function" ["&"] T_STRING
"(" parameter_list ")" "{" inner_statement_list "}" ;
class_declaration_statement = class_entry_type T_STRING
[extends_from] [implements_list] "{" {class_statement} "}"
| "interface" T_STRING [interface_extends_list] "{" {class_statement} "}" ;
class_entry_type = [ "abstract" | "final" ] "class" ;
extends_from = "extends" fully_qualified_class_name ;
interface_extends_list = "extends" interface_list ;
implements_list = "implements" interface_list ;
interface_list = fully_qualified_class_name { "," fully_qualified_class_name } ;
foreach_variable = ["&"] variable ;
for_statement = statement
| ":" inner_statement_list "endfor" ";" ;
foreach_statement = statement
| ":" inner_statement_list "endforeach" ";" ;
declare_statement = statement
| ":" inner_statement_list "enddeclare" ";" ;
declare_list = T_STRING "=" static_scalar { "," T_STRING "=" static_scalar } ;
switch_case_list = "{" [";"] {case_list} "}"
| ":" [";"] {case_list} "endswitch" ";" ;
case_list = "case" expr [":"|";"] inner_statement_list
| "default" [":"|";"] inner_statement_list ;
while_statement = statement
| ":" inner_statement_list "endwhile" ";" ;
elseif_branch = "elseif" "(" expr ")" statement ;
new_elseif_branch = "elseif" "(" expr ")" ":" inner_statement_list ;
else_single = "else" statement ;
new_else_single = "else" ":" inner_statement_list ;
parameter_list = [ parameter {"," parameter} ] ;
parameter = [T_STRING | "array"] ["&"] T_VARIABLE ["=" static_scalar] ;
function_call_parameter_list = [ function_call_parameter
{ "," function_call_parameter } ] ;
function_call_parameter = expr_without_variable
| variable
| "&" w_variable ;
global_var = T_VARIABLE
| "$" r_variable
| "$" "{" expr "}" ;
static_var = T_VARIABLE [ "=" static_scalar ] ;
class_statement = variable_modifiers class_variable_declaration
{"," class_variable_declaration} ";"
| "const" class_constant_declaration {"," class_constant_declaration} ";"
| {modifier} "function" ["&"] T_STRING "(" parameter_list ")"
method_body ;
method_body = ";"
| "{" inner_statement_list "}" ;
variable_modifiers = "var" | modifier {modifier} ;
modifier = "public" | "protected" | "private" | "static" | "abstract"
| "final" ;
class_variable_declaration = ("var" | modifier {modifier}) T_VARIABLE ["=" static_scalar] ;
class_constant_declaration = T_STRING "=" static_scalar ;
echo_expr_list = expr {"," expr} ;
for_expr = [ expr {"," expr} ] ;
expr_without_variable = "list" "(" assignment_list ")" "=" expr
| variable "=" expr
| variable "=" "&" variable
| variable "=" "&" "new" class_name_reference [ctor_arguments]
| "new" class_name_reference [ctor_arguments]
| "clone" expr
| variable ("+=" | "-=" | "*=" | "/=" | ".=" | "%=" | "&=" | "|=" |
"^=" | "<<=" | ">>=" ) expr
| rw_variable "++"
| "++" rw_variable
| rw_variable "--"
| "--" rw_variable
| expr ("||" | "&&" | "or" | "and" | "xor" | "|" | "&" | "^" | "." |
"+" | "-" | "*" | "/" | "%" | "<<" | ">>" | "===" | "!==" |
"<" | "<=" | ">" | ">=" ) expr
| ("+" | "-" | "!" | "~") expr
| expr "instanceof" class_name_reference
| "(" expr ")"
| expr "?" expr ":" expr
| internal_functions
| "(int)" expr
| "(double)" expr
| "(float)" expr
| "(real)" expr
| "(string)" expr
| "(array)" expr
| "(object)" expr
| "(bool)" expr
| "(boolean)" expr
| "(unset)" expr # FIXME: not implemented
| "exit" [exit_expr]
| "die" [exit_expr]
| "@" expr
| scalar
| "array" "(" [array_pair_list] ")"
| "`" encaps_list "`"
| "print" expr ;
function_call = T_STRING "(" function_call_parameter_list ")"
| fully_qualified_class_name "::" T_STRING
"(" function_call_parameter_list ")"
| fully_qualified_class_name "::" variable_without_objects
"(" function_call_parameter_list ")"
| variable_without_objects "(" function_call_parameter_list ")" ;
fully_qualified_class_name = T_STRING ;
class_name_reference = T_STRING
| dynamic_class_name_reference ;
dynamic_class_name_reference = base_variable "->" object_property
{ "->" object_property }
| base_variable ;
exit_expr = "(" [expr] ")" ;
ctor_arguments = "(" function_call_parameter_list ")" ;
common_scalar = T_LNUMBER | T_DNUMBER | T_CONSTANT_ENCAPSED_STRING
| "__LINE__" | "__FILE__" | "__CLASS__" | "__METHOD__" | "__FUNCTION__" ;
# FIXME: very bad syntax, $x = + + + 4; is valid!
static_scalar = common_scalar
| T_STRING
| "+" static_scalar
| "-" static_scalar
| "array" "(" [static_array_pair_list] ")"
| static_class_constant ;
static_class_constant = T_STRING "::" T_STRING ;
scalar = T_STRING
| T_STRING_VARNAME
| class_constant
| common_scalar
| "\"" encaps_list "\""
| "'" encaps_list "'"
| T_START_HEREDOC encaps_list T_END_HEREDOC ;
static_array_pair_list = static_array_pair { "," static_array_pair } [","] ;
static_array_pair = static_scalar ["=>" static_scalar] ;
expr = r_variable | expr_without_variable ;
r_variable = variable ;
w_variable = variable ;
rw_variable = variable ;
variable = base_variable_with_function_calls [ "->" object_property
method_parameters { "->" object_property method_parameters } ] ;
method_parameters = "(" function_call_parameter_list ")" ;
variable_without_objects = reference_variable
| simple_indirect_reference reference_variable ;
static_member = fully_qualified_class_name "::" variable_without_objects ;
base_variable_with_function_calls = base_variable | function_call ;
base_variable = reference_variable
| simple_indirect_reference reference_variable
| static_member ;
reference_variable = compound_variable { selector } ;
compound_variable = T_VARIABLE | "$" "{" expr "}" ;
selector = "[" [expr] "]" | "{" expr "}" ;
object_property = variable_name { selector }
| variable_without_objects ;
variable_name = T_STRING | "{" expr "}" ;
simple_indirect_reference = "$" {"$"} ;
assignment_list = [assignment_list_element] {"," [assignment_list_element]} ;
assignment_list_element = variable
| "list" "(" assignment_list ")" ;
array_pair_list = array_pair {"," array_pair} [","] ;
array_pair = "&" w_variable
| expr "=>" "&" w_variable
| expr "=>" expr ;
encaps_list =
{
encaps_var
| T_STRING
| T_NUM_STRING
| T_ENCAPSED_AND_WHITESPACE
| T_CHARACTER
| T_BAD_CHARACTER
| "["
| "]"
| "{"
| "}"
| "->"
} ;
encaps_var = T_VARIABLE [ "[" encaps_var_offset "]" ]
| T_VARIABLE "->" T_STRING
| "${" expr "}"
| "${" T_STRING_VARNAME "[" expr "]" "}"
| T_CURLY_OPEN variable "}" ;
encaps_var_offset = T_STRING | T_NUM_STRING | T_VARIABLE ;
internal_functions = "isset" "(" variable {"," variable} ")"
| "empty" "(" variable ")"
| "include" expr
| "include_once" expr
| "eval" "(" expr ")"
| "require" expr
| "require_once" expr ;
class_constant = fully_qualified_class_name "::" T_STRING ;
LABEL = (letter | "_") {letter | digit | "_"} ;
T_STRING = LABEL;
T_BAD_CHARACTER = "\x00".."\x08" | "\x0b" | "\x0c" | "\x0e".."\x1f" ;
T_VARIABLE = "$" T_STRING ;
T_LNUMBER = octal | decimal | hexadecinal ;
octal = "0" {"0".."7"} ;
decimal = "1".."9" {digit} ;
hexadecinal = "0x" hexdigit {hexdigit} ;
digit = "0".."9" ;
hexdigit = digit | "a".."f" | "A".."F" ;
letter = "a".."z" | "A".."Z" | "\x7f".."\xff" ;
T_DNUMBER = DNUM | EXPONENT_DNUM;
DNUM = digit ["."] digit {digit} | digit {digit} ["."] {digit};
EXPONENT_DNUM = (LNUM | DNUM) ("e"|"E") ["+"|"-"] LNUM;
LNUM = digit {digit};
T_CURLY_OPEN = "${";
T_CONSTANT_ENCAPSED_STRING = single_quoted_constant_string | double_quoted_constant_string;
# FIXME
single_quoted_constant_string =
"'" { "any char except ' and \\" | "\\" "any char" } "'";
# FIXME
double_quoted_constant_string =
"\"" { "any char except $ \" and \\" | "\\" "any char" } "\"";
T_STRING_VARNAME = LABEL;
T_NUM_STRING = LNUM | hexadecinal;
T_START_HEREDOC = "<<<<" {" "|"\t"} LABEL NEWLINE;
NEWLINE = "\r"|"\n"|"\r\n";
T_END_HEREDOC = "FIXME: here at the beginning of the line"
LABEL [";"] NEWLINE;
</code></figure>
</section>
</main>
<footer>Namdak Tonpa <span class="heart"> ❤ </span> 2009—2020</footer>
</body>
</html>