??? ??????? ???? ?? ??? ??? ???? ? ???? ?? ???????. ? ???? PHP?? ??? ???? ??? ????? ? ???? ? ??? ?????.
PHP ?? ??? pcntl
? posix
??? ?? ??? ? ????. pcntl
與 posix
擴展實現(xiàn)。
編程中需要注意的地方有:
- 通過二次
pcntl_fork()
以及posix_setsid
讓主進程脫離終端 - 通過
pcntl_signal()
忽略或者處理SIGHUP
信號 - 多進程程序需要通過二次
pcntl_fork()
或者pcntl_signal()
忽略SIGCHLD
信號防止子進程變成 Zombie 進程 - 通過
umask()
設定文件權限掩碼,防止繼承文件權限而來的權限影響功能 - 將運行進程的
STDIN/STDOUT/STDERR
重定向到/dev/null
或者其他流上
如果要做的更好,還需要注意:
- 如果通過 root 啟動,運行時更換到低權限用戶身份
- 及時
chdir()
防止操作錯誤路徑 - 多進程程序考慮定時重啟,防止內存泄露
什么是daemon
文章的主角守護進程(daemon),Wikipedia 上的定義是:
在一個多任務的電腦操作系統(tǒng)中,守護進程(英語:daemon,/?di?m?n/或/?de?m?n/)是一種在后臺執(zhí)行的電腦程序。此類程序會被以進程的形式初始化。守護進程程序的名稱通常以字母“d”結尾:例如,syslogd就是指管理系統(tǒng)日志的守護進程。
通常,守護進程沒有任何存在的父進程(即PPID=1),且在UNIX系統(tǒng)進程層級中直接位于init之下。守護進程程序通常通過如下方法使自己成為守護進程:對一個子進程運行fork,然后使其父進程立即終止,使得這個子進程能在init下運行。這種方法通常被稱為“脫殼”。
UNIX環(huán)境高級編程(第二版)(以下使用簡稱 APUE 指代) 13章有云:
守護進程也成精靈進程( daemon )是生存周期較長的一種進程。它們常常在系統(tǒng)自舉時啟動,僅在系統(tǒng)關閉時才終止。因為他們沒有控制終端,所以說他們是在后臺運行的。
這里注意到,daemon有如下特征:
- 沒有終端
- 后臺運行
- 父進程 pid 為1
想要查看運行中的守護進程可以通過 ps -ax
或者 ps -ef
查看,其中 -x
表示會列出沒有控制終端的進程。
實現(xiàn)關注點
二次 fork 與 setsid
fork 系統(tǒng)調用
fork 系統(tǒng)調用用于復制一個與父進程幾乎完全相同的進程,新生成的子進程不同的地方在于與父進程有著不同的 pid 以及有不同的內存空間,根據代碼邏輯實現(xiàn),父子進程可以完成一樣的工作,也可以不同。子進程會從父進程中繼承比如文件描述符一類的資源。
PHP 中的 pcntl
擴展中實現(xiàn)了 pcntl_fork()
函數(shù),用于在 PHP 中 fork 新的進程。
setsid 系統(tǒng)調用
setsid 系統(tǒng)調用則用于創(chuàng)建一個新的會話并設定進程組 id。
這里有幾個概念:會話
,進程組
。
在 Linux 中,用戶登錄產生一個會話(Session),一個會話中包含一個或者多個進程組,一個進程組又包含多個進程。每個進程組有一個組長(Session Leader),它的 pid 就是進程組的組 id。進程組長一旦打開一個終端,這一個終端就被稱為控制終端。一旦控制終端發(fā)生異常(斷開、硬件錯誤等),會發(fā)出信號到進程組組長。
后臺運行程序(如 shell 中以&
結尾執(zhí)行指令)在終端關閉之后也會被殺死,就是沒有處理好控制終端斷開時發(fā)出的SIGHUP
信號,而SIGHUP
- ? ??
pcntl_fork()
?posix_setsid
? ???? ?? ????? ?????. ??? -
pcntl_signal()
? ??SIGHUP
??? ????? ?????. - ?? ???? ?????
? ? ? ???? ???. >pcntl_fork()
?? pcntl_signal()SIGCHLD
??? ???? ?? ????? ?? ????? ?? ?? ?????. - ?? ?? ?? ???? ??? ??? ??? ??? ??? ???
umask()
? ?? ?? ??? - ?? ?? ?????
STDIN/STDOUT/STDERR
? ???? ???????./dev/null
?? ?? ????
- ??? ?? ???? ?? , ??? ? ?? ??? ??? ID? ??
- ???
chdir()
?? ?? ?? - ??? ??? ????? ?? ???? ????? ????? ?? ???? ?? ????
???? ?????
????? ??? ?? Wikipedia? ??? ??? ????. ????????? ??? ?? ???? ??(??: daemon, /?di?m?n/ ?? /?de?de?m?n/)? ??????? ???? ??? ???????. ??? ????? ????? ??????. ?? ????? ??? ????? ?? "d"? ????. ?? ?? syslogd? ??? ??? ???? ??? ?????.??UNIX ??? ?? ?????(?2?)(?? ??) APUE? ???) 13?? ??
????? ?? ?????? ?? ?? ????(?, PPID=1)? ??? UNIX ??? ???? ???? init ?? ??? ????. ?? ????? ????? ?? ?????? ??? ??? ?? ?? ????? init?? ??? ? ??? ?? ????? ?? ???? ????? ??? ????. ? ??? ?? "??"??? ???. ??
?? ?? ????? ?? ????(daemon)??, ????? ? ?????? ???. ???? ??? ? ???? ???? ??? ?? ???? ??? ????. ?? ???? ?? ??? ??????? ????? ???. ??????? ??? ?? ??? ??? ????: ??
- ??? ??
- ??????? ??
- ?? ???? pid? 1???. ???? ?? ?? ????? ???
- 控制終端斷開,SIGHUP 發(fā)送到進程組組長
- 進程組組長退出,SIGHUP 會發(fā)送到進程組中的前臺進程
- SIGHUP 常被用于通知進程重載配置文件(APUE 中提及,daemon 由于沒有控制終端,被認為不可能會收到這一個信號,所以選擇復用)
- 父進程處理
SIGCHLD
PHP? - daemon 不應使用標準流
- 0/1/2 要設定成 /dev/null
ps -ax
?? ps -ef
? ?? ? ? ????. ??? -x
? ????? ?????. ???? ???? ??????? ????. ???? ?? ??
??? ?? ?? ? ?? ID???? ?? ??? ???????? ??? ??? ?? ????? ?? ??? ????? ???? ? ?????. ?? ??? ?? ????? ?? ????? ???? ?? ??? ?? pid? ??? ??? ???? ????. ?? ????? ?? ????? ??? ????? ??? ?? ????. ?? ????? ?? ??????? ?? ???? ?? ???? ??????. ????PHP?pcntl
??? PHP?? ? ????? ???? ? ???? pcntl_fork()
??? ?????. ????setsid ??? ??????setsid ??? ??? ? ??? ???? ???? ?? ID? ???? ? ?????. ???????? ??
, ???? ??
? ?? ?? ??? ????. ????Linux??? ??? ???? ??? ?????. ???? ?? ??? ???? ??? ???? ???? ???? ?? ????? ?????. ? ???? ???? ?? ??? ??? ?? pid? ???? ??? ?? ID???. ???? ??? ???? ?? ? ???? ?? ?????? ???. ?? ????? ??(?? ??, ???? ?? ?)? ???? ???? ?? ???? ??? ?????. ????????? ?? ????(?: &
? ??? ? ?? ??)? ???? ?? ?? ?????. > ??? ???? ???? ????? ?? SIGHUP
??? ?? ??? ????? ???? ????. ??setsid
??? ??? ??? ? ?? ????? ? ???? ??? ?????. ?? ?????? ???? ??? ??? ? ???? ??? ?? ???? ????. ???? ?? ????? ???? ??? ????. setsid
系統(tǒng)調用之后,會讓當前的進程新建一個進程組,如果在當前進程中不打開終端的話,那么這一個進程組就不會存在控制終端,也就不會出現(xiàn)因為關閉終端而殺死進程的問題。
PHP 中的 posix
擴展中實現(xiàn)了 posix_setsid()
函數(shù),用于在 PHP 中設定新的進程組。
孤兒進程
父進程比子進程先退出,子進程就會變成孤兒進程。
init 進程會收養(yǎng)孤兒進程,即孤兒進程的 ppid 變?yōu)?1。
二次 fork 的作用
首先,setsid
系統(tǒng)調用不能由進程組組長調用,會返回-1。
二次 fork 操作的樣例代碼如下:
$pid1 = pcntl_fork(); if ($pid1 > 0) { exit(0); } else if ($pid1 < 0) { exit("Failed to fork 1\n"); } if (-1 == posix_setsid()) { exit("Failed to setsid\n"); } $pid2 = pcntl_fork(); if ($pid2 > 0) { exit(0); } else if ($pid2 < 0) { exit("Failed to fork 2\n"); }
假定我們在終端中執(zhí)行應用程序,進程為 a,第一次 fork 會生成子進程 b,如果 fork 成功,父進程 a 退出。b 作為孤兒進程,被 init 進程托管。
此時,進程 b 處于進程組 a 中,進程 b 調用 posix_setsid
要求生成新的進程組,調用成功后當前進程組變?yōu)?b。
此時進程 b 事實上已經脫離任何的控制終端,例程:
<?php cli_set_process_title('process_a'); $pidA = pcntl_fork(); if ($pidA > 0) { exit(0); } else if ($pidA < 0) { exit(1); } cli_set_process_title('process_b'); if (-1 === posix_setsid()) { exit(2); } while(true) { sleep(1); }
執(zhí)行程序之后:
? ~ php56 2fork1.php ? ~ ps ax | grep -v grep | grep -E 'process_|PID' PID TTY STAT TIME COMMAND 28203 ? Ss 0:00 process_b
從 ps 的結果來看,process_b 的 TTY 已經變成了 ?
,即沒有對應的控制終端。
代碼走到這里,似乎已經完成了功能,關閉終端之后 process_b 也沒有被殺死,但是為什么還要進行第二次 fork 操作呢?
StackOverflow 上的一個回答寫的很好:
The second fork(2) is there to ensure that the new process is not a session leader, so it won’t be able to (accidentally) allocate a controlling terminal, since daemons are not supposed to ever have a controlling terminal.
這是為了防止實際的工作的進程主動關聯(lián)或者意外關聯(lián)控制終端,再次 fork 之后生成的新進程由于不是進程組組長,是不能申請關聯(lián)控制終端的。
綜上,二次 fork 與 setsid 的作用是生成新的進程組,防止工作進程關聯(lián)控制終端。
SIGHUP 信號處理
一個進程收到 SIGHUP
信號的默認動作是結束進程。
而 SIGHUP
會在如下情況下發(fā)出:
由于實際的工作進程不在前臺進程組中,而且進程組的組長已經退出并且沒有控制終端,不處理正常情況下當然也沒有問題,然而為了防止偶然的收到 SIGHUP
導致進程退出,也為了遵循守護進程程序設計的慣例,還是應當處理這一信號。
Zombie 進程處理
何為 Zombie 進程
簡單來說,子進程先于父進程退出,父進程沒有調用 wait
系統(tǒng)調用處理,進程變?yōu)?Zombie 進程。
子進程先于父進程退出時,會向父進程發(fā)送 SIGCHLD
信號,如果父進程沒有處理,子進程也會變?yōu)?Zombie 進程。
Zombie 進程會占用可 fork 的進程數(shù),Zombie 進程過多會導致無法 fork 新的進程。
此外,Linux 系統(tǒng)中 ppid 為 init 進程的進程,變?yōu)?Zombie 后會由 init 進程回收管理。
Zombie 進程的處理
從 Zombie 進程的特點,對于多進程的daemon,可以通過兩個途徑解決這一問題:
posix
??? PHP?? ? ???? ??? ???? ? ???? posix_setsid()
??? ?????. ?? ????? ?? ?????? ?? ???? ?? ????? ?? ????? ???.
init ????? orphan ????? ?????. ?, orphan ????? ppid? 1? ???. ?? ??? ??
?? setsid
??? ??? ???? ?? ??? ??? ? ??? -1? ?????.
? ?? ?? ??? ?? ??? ??? ????. ? ~ cat test_umask.php
<?php
chdir('/tmp');
umask(0066);
mkdir('test_umask', 0777);
? ~ php test_umask.php
? ~ ll /tmp | grep umask
drwx--x--x 2 root root 4.0K 8月 22 17:35 test_umask
????? ??????? ???? ????? ??? ??? ?????. ? ?? ??? ?? ????? ?????. b. ??? ???? ?? ????? ?????. a? ???. b ?? ?????? init ????? ?? ??????.
?? ???? b? ???? ?? a? ?? ???, ???? b? posix_setsid
? ???? ??? ??? ? ?? ???? ??? b? ???. ?? ???? b? ??? ?? ?? ???? ?????. ??:
???? ?? ?:
? ~ strace -p 6723 Process 6723 attached - interrupt to quit restart_syscall(<... resuming interrupted call ...>) = 0 write(1, "1503417004\n", 11) = 11 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 nanosleep({10, 0}, 0x7fff71a30ec0) = 0 write(1, "1503417014\n", 11) = -1 EIO (Input/output error) close(2) = 0 close(1) = 0 munmap(0x7f35abf59000, 4096) = 0 close(0) = 0??ps ???? process_b? TTY?? ?????
?, ?? ?? ???? ????. ????? ???? ??? ??? ??? ? ????. process_b? ???? ?? ??? ???? ???? ? ?? ?? ??? ?? ??? ?????? ????A answer??StackOverflow? ? ???????:?????? ? ?? ?? (2) ? ????? ?? ??? ???? ??? ?? ???? ?? ? ???? (???) ?? ???? ??? ? ??? ?? ?? ????.???? ????? ?? ?? ????? ?? ???? ????? ????? ??? ???? ?? ???? ?? ?? ??? ? ??? ? ????? ???? ??? ??? ??? ??? ?? ????? ??? ??? ? ????. ????????? ?? ??? setid? ??? ??? ???? ??? ???? ?? ????? ?? ???? ???? ?? ???? ????. ????????SIGHUP ?? ?? ????????SIGHUP
??? ?? ????? ?? ??? ????? ???? ????. ???????SIGHUP
? ?? ???? ?????: ?????? ???? ??? ???? SIGHUP? ???? ?? ???? ?????. ???????? ?? ??? ???? SIGHUP? ????? ???? ??? ????? ???? ????SIGHUP? ?? ??? ?? ????? ????? ??? ? ?? ?????(APUE?? ??? ???? ?? ???? ???? ? ??? ???? ?? ?????? ???? ??? ?????). ???) ???????? ?? ????? ????? ???? ??? ??, ???? ??? ??? ???? ?? ???? ?? ??? ??? ????? ???? ??? ??? ????. ??? ????? ???
SIGHUP
? ???? ????? ???? ?? ????? ?? ????? ??? ??? ?? ? ??? ?? ???? ???. ?????????? ???? ?????????????? ????? ?????????????? ???, ?? ????? ?? ?????? ?? ????, ?? ?????wait
??? ?? ??? ???? ????. , ????? ?? ????? ???. ?????? ????? ?? ?????? ?? ???? ?? ?????SIGCHLD
??? ????. ?? ????? ?? ???? ??? ?? ????? ?? ????? ???. ?????? ????? ??? ? ?? ???? ?? ?????. ?? ????? ?? ??? ??? ????? ??? ? ?? ???. ?????? Linux ?????? ppid? init ????? ????? ??? ? ? init ????? ?? ??? ? ?????. ???????? ???? ?????????? ????? ??? ?? ???? ??? ?? ? ??? ? ?? ???? ??? ? ????. ?????? ?????
SIGCHLD
? ?????. signal?? ???? ????? init? ?? ???? ??????????? ????? ?? ??? ?? ? ?? ?? ?? ?? ?? ?? ??? ???? ??? ???? ????? ?? ???. ????init? ?? ????? ????? ?? ??? ? ? ??? ? ????. ??? ? ?? ??? ?? ???? a? ?? ?? ???? b? ???? ?? ???? b? ?? ? ????. ?? ????? ?? ???? init ????? ?? ???? ? ????. ????????umask????????umask? ?? ?????? ???? ??? ??? ??? ??? ????. ????PHP ??Manual?? ??: ??????umask()? PHP? umask? ??? & 0777? ???? ?? umask? ?????. PHP? ?? ??? ???? ? ?? ?? umask? ?????. ???????? ????? umask? ??? ???? ??? ?? ?? ??? ??? ? ??? ?? ??? ?????. ??? ~ cat test_umask.php <?php chdir('/tmp'); umask(0066); mkdir('test_umask', 0777); ? ~ php test_umask.php ? ~ ll /tmp | grep umask drwx--x--x 2 root root 4.0K 8月 22 17:35 test_umask所以,為了保證每一次都能按照預期的權限操作文件,需要置0 umask 值。
重定向0/1/2
這里的0/1/2分別指的是
STDIN/STDOUT/STDERR
,即標準輸入/輸出/錯誤三個流。樣例
首先來看一個樣例:
上述代碼幾乎完成了文章最開始部分提及的各個方面,唯一不同的是沒有對標準流做處理。通過
php not_redirect_std_stream_daemon.php
指令也能讓程序在后臺進行。在
sleep
的間隙,關閉終端,會發(fā)現(xiàn)進程退出。通過
strace
觀察系統(tǒng)調用的情況:? ~ strace -p 6723 Process 6723 attached - interrupt to quit restart_syscall(<... resuming interrupted call ...>) = 0 write(1, "1503417004\n", 11) = 11 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 nanosleep({10, 0}, 0x7fff71a30ec0) = 0 write(1, "1503417014\n", 11) = -1 EIO (Input/output error) close(2) = 0 close(1) = 0 munmap(0x7f35abf59000, 4096) = 0 close(0) = 0發(fā)現(xiàn)發(fā)生了 EIO 錯誤,導致進程退出。
原因很簡單,即我們編寫的 daemon 程序使用了當時啟動時終端提供的標準流,當終端關閉時,標準流變得不可讀不可寫,一旦嘗試讀寫,會導致進程退出。
在信海龍的博文《一個echo引起的進程崩潰》中也提到過類似的問題。
解決方案
APUE 樣例
APUE 13.3中提到過一條編程規(guī)則(第6條):
某些守護進程打開
/dev/null
時期具有文件描述符0、1和2,這樣,任何一個視圖讀標準輸入、寫標準輸出或者標準錯誤的庫例程都不會產生任何效果。因為守護進程并不與終端設備相關聯(lián),所以不能在終端設備上顯示器輸出,也無從從交互式用戶那里接受輸入。及時守護進程是從交互式會話啟動的,但因為守護進程是在后臺運行的,所以登錄會話的終止并不影響守護進程。如果其他用戶在同一終端設備上登錄,我們也不會在該終端上見到守護進程的輸出,用戶也不可期望他們在終端上的輸入會由守護進程讀取。簡單來說:
例程中使用:
for (i = 0; i < rl.rlim_max; i++) close(i); fd0 = open("/dev/null", O_RDWR); fd1 = dup(0); fd2 = dup(0);實現(xiàn)了這一個功能。
dup()
(參考手冊)系統(tǒng)調用會復制輸入參數(shù)中的文件描述符,并復制到最小的未分配文件描述符上。所以上述例程可以理解為:關閉所有可以打開的文件描述符,包括標準輸入輸出錯誤; 打開/dev/null并賦值給變量fd0,因為標準輸入已經關閉了,所以/dev/null會綁定到0,即標準輸入; 因為最小未分配文件描述符為1,復制文件描述符0到文件描述符1,即標準輸出也綁定到/dev/null; 因為最小未分配文件描述符為2,復制文件描述符0到文件描述符2,即標準錯誤也綁定到/dev/null;復制代碼開源項目實現(xiàn):Workerman
Workerman 中的 Worker.php 中的
resetStd()
方法實現(xiàn)了類似的操作。/** * Redirect standard input and output. * * @throws Exception */ public static function resetStd() { if (!self::$daemonize) { return; } global $STDOUT, $STDERR; $handle = fopen(self::$stdoutFile, "a"); if ($handle) { unset($handle); @fclose(STDOUT); @fclose(STDERR); $STDOUT = fopen(self::$stdoutFile, "a"); $STDERR = fopen(self::$stdoutFile, "a"); } else { throw new Exception('can not open stdoutFile ' . self::$stdoutFile); } }Workerman 中如此實現(xiàn),結合博文,可能與 PHP 的 GC 機制有關,對于 fd 0 1 2來說,PHP 會維持對這三個資源的引用計數(shù),在直接 fclose 之后,會使得這幾個 fd 對應的資源類型的變量引用計數(shù)為0,導致觸發(fā)回收。所需要做的就是將這些變量變?yōu)槿肿兞?,保證引用的存在。
推薦學習:《PHP視頻教程》
? ??? ???? ?????? PHP?? ??? ???? ??? ??????? ?? ?????. ??? ??? PHP ??? ????? ?? ?? ??? ?????!

? AI ??

Undress AI Tool
??? ???? ??

Undresser.AI Undress
???? ?? ??? ??? ?? AI ?? ?

AI Clothes Remover
???? ?? ???? ??? AI ?????.

Clothoff.io
AI ? ???

Video Face Swap
??? ??? AI ?? ?? ??? ???? ?? ???? ??? ?? ????!

?? ??

??? ??

???++7.3.1
???? ?? ?? ?? ???

SublimeText3 ??? ??
??? ??, ???? ?? ????.

???? 13.0.1 ???
??? PHP ?? ?? ??

???? CS6
??? ? ?? ??

SublimeText3 Mac ??
? ??? ?? ?? ?????(SublimeText3)

??? ?? ??? ??? ?? JavaScript? MediareCorder API? ?? PHP ???? ???? ?????. 2. PHP? ???? ?? ??? ???? STTAPI (? : Google ?? Baidu ?? ??)? ???? ???? ?????. 3. PHP? ???? AI ??? (? : OpenAigpt)? ????. 4. ?? ?? PHP? TTSAPI (? : Baidu ?? Google ?? ??)? ???? ??? ?? ??? ?????. 5. PHP? ?? ??? ??? ??? ??? ?? ?? ??? ?????. ?? ????? PHP? ?? ???? ?? ?? ?? ??? ??? ?????.

PHP?? ?? ?? ??? ???? ?? ??? ? ???? ?? ??? ???? ?? ??? ???? ???? ????. 1. ?? ?? ??? ?? ??? URL ? ?? ??? ????. 2. UrlenCode? ???? ?? ??? ???????. 3. ? ???? ????? ?? ?? ??? ? ?? ??? ?????. 4. ???? ???? ?? ? ? ??? ??? ??? ??? ?????. 5. ??? ?? ??? ????? ?? ????? OG ??? ???? ?????. 6. XSS ??? ???? ?? ??? ??? ?????. ? ???? ??? ??? ???? ??? ?? ?? ??? ??? ???? ??? ?? ??? ?????.

AI? ??? ??? ?? ?? ? ?? ???? ????? ?? ??? ??????. 1. Baidu, Tencent API ?? ?? ?? NLP ?????? ?? ??? AI ?? ?? API? ??????. 2. PHP? ? ?? guzzle? ?? API? ???? ?? ??? ??????. 3. ?? ????? ?? ?? ??? ???? ???? ???? ??? ??? ? ????. 4. ?? ?? ? ?? ???? ?? PHP-L ? PHP_CODESNIFFER? ??????. 5. ???? ????? ???? ?? ?? ??? ?????? ??? ??????. AIAPI? ??? ? ???, ?? ??, ?? ? PHP ?? ??? ??? ???. ?? ???? PSR ??? ???, ??? ????? ????, ?? ??? ???, ????? ??? ????, X? ???????.

1. ?? ???? ??? ??? ?????? ?? ?? ??? ??, ??? ?? ???? ??? (? : ?? ???, ? ? ??), ?? ??? ?? ???? ???? ? ?? ?? ??? ??? ?? ??? ????????. 2. ?? ??? ??? ?? ? ??? ???? ?? ?? ?? ???? ?? ? ?? AUDIT ?? ??? ??? ? ????? ????? ??? ???????. 3. ?? ?? ??? ?? ??? ???????. Recaptchav3 ???? ??, ??? ?? ?? ?? ?? ??, IP ? ?? ??? ??? ??? ?? ???? ??? ?? ??? ????? ??? ???? ????? ??? ?????.

PHP? AI ??? ??? ?? ????? ??? API? ?? ?????. ??? ??? ????? ? ??? ???? ?????. API ??? ?? ?? ??? ???? ??? ??? ???? ???? ? ????. 2. ?? ?? ???? guzzle ?? curl? ???? HTTP ??? ???, JSON ??? ??? ? ???, API ? ?? ??, ??? ? ?? ??? ???? ??, ??? ?? ?? ? ? ?? ????, ??? ?? ? ?????? ?????. 3. ???? ???? ?? ???? API ??, ?? ? ??? ?? ??, ??? ?? ??, ?? ?? ? ??? ??? ??? ?????. ?? ??? ??? ??? ? ??? ???? Propt ?? ? ?? ?? ??, ??? ?? ? ?? ????, ?? ?? ?? ???? ? ??? ?? ? ???? ????? ?????.

PHP? ?????? ????? ?? ?? ?? ???? ???? ?? ???? ???? ?? ?? ???? ?????. 2. ?? ??? ???? ???? ?? ??? ?? ? ??? ??? ???? ?? API/Webhook ??? ??? ?? ???? ??? ??? ??? ??? ?????. 3. ?? ????? ?? ??, ??/???? ????, ???? ??, ???? ? ??? ?????? ????? ?? ??? ???? ???? ?? Dingtalk, SMS ?? ??? ???? ??? ?????? ???? ?? ? ??? ??? ????? ?? ??? ???? ???????.

PhpisstillRelevantinmodernenterpriseenvironments.1. Modernphp (7.xand8.x)? ??? ??, ??? ??, jitcompilation ? modernsyntax, mateitsuilableforlarge-scalepplications

MAC ?? ???? ? ??? ?? ??? ????? ?? ? ??? ????? ????. 1. ???? ???? ???? ???? ??? ?? ? ?? ????? ??? ???? ??????. 2. ????? ?? ?? ? ??? ???? ???? ?? ?? ????? ??? ???? ?????. 3. ??? ?? ??? ???? ?? ???? ?? ???? ?? ???? ?? ? ? ????. 4. ??? ????? ????? ? ?? ?? ? ??? ?? ? ??? ??????.
