SlideShare a Scribd company logo
PHP と
SAPI と
ZendEngine3 と
2018/03/09
PHPerKaigi 2018
do_aki
@do_aki
@do_aki
http://do-aki.net/
はじめに
<?php
declare(strict_types=1);
function hello(
string $name):void
{
echo "hello {$name}";
}
hello('php');
PHP スクリプト PHP 実行環境 PHP プログラムの実行
hello php
はじめに
<?php
declare(strict_types=1);
function hello(
string $name):void
{
echo "hello {$name}";
}
hello('php');
PHP スクリプト PHP 実行環境 PHP プログラムの実行
hello php
トークする内容はここ
目次
1. Server API (SAPI)
2. Zend Thread Safety (ZTS)
3. Zend Engine
3.1 Virtual Machine (PHP VM)
3.2 Memory Allocator & Garbage Collector
Server API (SAPI)
PHP プログラムの実行とは
<?php
declare(strict_types=1);
function hello(
string $name):void
{
echo "hello {$name}";
}
hello('php');
PHP スクリプト
(テキストファイル)
PHP 実行環境
(ソフトウェア)
実行環境がなければ、 PHPスクリプトは ただのテキスト
PHP プログラムの実行
hello php
Webサーバと組み合わせて実行
(Web Server起動
時にロード済み)
Web Server
run PHP
Script
HTTP Request
Web Server
組み込み型
Web
Server
CGI Protocol
run PHP
Script
HTTP Request
CGI型
起動して実行
Web
Server
FastCGI Protocol
run PHP
Script
HTTP Request
FastCGI型
起動済み
PHP 単体で実行
Built-in WebServer
(ex:php –S 127.0.0.1:3000) run PHP
Script
Webサーバと組み合わせずにスタンドアロンで動作
(Built-in Web Server は IO 多重化による、シングルプロセス実装なのでIO が Busy に
なると並列処理できない。もし PHP Script 実行時にクラッシュすると、WebServer も巻
き込んで死ぬのであくまで開発用)
HTTP Request
Command Execution
run PHP
Script
コマンド実行
(ex: php hoge.php)
起動して実行
複数ある PHP の実体(バイナリ)
主なファイル名 説明 [SAPI]
libphp7.so
php7apache2_4.dll
Apache httpd のモジュールとして実行される PHP(ラ
イブラリ) いわゆる mod_php [apache2handler]
php-cgi
php-cgi.exe
いわゆる CGI版 PHP。CGIプロトコルだけでなくFastCGI
プロトコルも実装した PHP (実行ファイル) [cgi-fcgi]
php-fpm
高負荷環境に対応したプロセス管理を備えた、FastCGI
プロトコル実装の PHP (実行ファイル) [fpm-fcgi]
php
php.exe
php コマンド。 built in web server もこれで起動で
きる (実行ファイル) [cli] [cli-server]
phpdbg
phpdbg.exe
PHP の組み込みデバッガ (実行ファイル) [phpdbg]
libphp7.so
php7embed.lib
他のアプリケーションに組み込んで PHP を実行すること
ができるようになるライブラリ [embed]
lsphp
LiteSpeed の LSAPI を実装した PHP (実行ファイル)
[litespeed]
SAPI と SAPI module
PHP コア
(Zend Engine)
SAPI
module
SAPI
Web
Server
or
Shell
apache2
handler
or
php-fpm
or
cli
or
etc…
PHP
Scri
pt
mod_php の場合
PHP コア
(Zend Engine)
SAPI
module
SAPIApache
httpd
apache2
handler PHP
Scri
pt
php-fpm の場合
PHP コア
(Zend Engine)
SAPI
module
SAPI
FastCGI
supported
Web
Server
(ex:nginx)
fpm-
fcgi PHP
Scri
pt
php コマンド の場合
PHP コア
(Zend Engine)
SAPI
module
SAPIShell
cli PHP
Scri
pt
SAPI と SAPI module
PHP コア
(Zend Engine)
SAPI
module
SAPI
様々な
Web
Server
Web
Server
ごとの違
いを吸収
PHP
Scri
pt
異な
る通
信方
式に
対応
PHPコアを起動するための
ブートストラップでもある
Server API (SAPI)
• Web サーバごとの違いを吸収して、様々な Webサーバで
PHP 実行環境を利用可能にする仕組み
• これを実装した SAPI module が PHP 実行環境のブートス
トラップとなる
– 以前は Web サーバごとに数多く存在していたが、現在は Web
サーバ - アプリケーションサーバ間のプロトコルが共通化して
きたため少数
– 現在は、ほとんど動作方式の違いでしかない
– SAPI module のことを指して SAPI と呼ぶこともある
SAPI module (PHP7.2)
• apache2handler (Apache 2.0 Handler)
• cli (Command Line Interface)
• cli-server (Built-in HTTP server)
• phpdbg (phpdbg)
• fpm-fcgi (FPM/FastCGI)
• embed (PHP Embedded Library)
• cgi-fcgi (CGI/FastCGI)
• litespeed (LiteSpeed V6.11)
※括弧は pretty name
SAPI module (PHP5.6)
apache2handler (Apache 2.0 Handler) / cli (Command
Line Interface) / cli-server (Built-in HTTP server)
/ phpdbg (phpdbg) / fpm-fcgi (FPM/FastCGI) / embed
(PHP Embedded Library) / cgi-fcgi (CGI/FastCGI) /
litespeed (LiteSpeed V6.10)
↑ PHP7 にもある/↓ PHP7で公式リポジトリからは削除された
aolserver (AOLserver) / apache (Apache) /
apache_hooks (Apache1) / apache2filter (Apache 2.0
Filter) / isapi (IIS) / caudium (Caudium) /
Continuity (Continuity Server Enterprise Edition) /
milter (Sendmail Milter SAPI) / nsapi (NSAPI) /
phttpd (PHTTPD) / pi3web (PI3WEB) / roxen (Roxen) /
thttpd (thttpd) / tux (tux) / webjames (WebJames)
SAPI module の役割
• POSTやCookieデータの読み込み (read_post,read_cookie)
• 環境変数の読み込み (getenv)
• 出力制御 (ub_write,flush)
• ヘッダ出力 (header_handler,send_headers, send_header)
• 設定ファイル(php.ini)の扱い制御
– デフォルトパスの上書き (php_ini_path_override)
– 読み込まない設定 (php_ini_ignore, php_ini_ignore_cwd)
etc…
SAPI module の役割ではないこと
• ネットワーク接続
– socket 接続
– DB 接続
• ファイル入出力
– ファイルシステムへのアクセス
• プロセス間通信
– signal
– pipe (shell_exec)
多くは Zend Engine のストリームAPI (一部は拡張が直接制御)
SAPI module による出力制御
<?php
header("HTTP/1.0 418 I'm a tea pot");
echo "Hello World!";
Hello World! Hello World!
• apache2handler (mod_php)
の場合は apache httpd の関
数(ap_rwrite等) 呼び出し
• fpm-fcgi (fpm) の場合は
FastCGI protocol による
socket への書き込み
• cli の場合は write
system call の呼び出し
(header 出力は無視)
PHP Script
設定ファイル(php.ini) のデフォルトパス
• SAPI module ごとに異なる
– コンパイル時に指定できる
• ディストリビューションのパッケージで提供されているもの
はだいたい一貫してる
• コンパイル済みのバイナリを利用する場合、それぞれ異なる
php.ini ファイルを参照する可能性があるので注意
– cli と php-fpm とで違う php.ini を見ているとかありうる
単一バイナリに 複数の SAPI module
php(.exe)
libphp.so
php hoge.php
php –S 127.0.0.1:3000
cli SAPI
cli-server
SAPI
(--enable-cli)
--enable-embed
(unit SAPI)
そのまま利用
一部利用して実装
[Any App]
(embed SAPI)
同じ SAPI module で異なる動作
php-cgi
lsphp
php-cgi hoge.php
php-cgi –b 127.0.0.1:9000
CGI として実行
FastCGI (待ち受け)
(--enable-cgi)
--with-litespeed
cgi-fcgi
SAPI
(内部的には別処理)
lsphp hoge.php
lsphp –b 127.0.0.1:3000
ファイルを指定して実行
litespeed
SAPI
(内部的には別処理)
LSAPI Server mode
利用している SAPI を知る方法
• (実行ファイルの場合) –v オプションを付けて実行
• php_sapi_name() の戻り値 あるいは PHP_SAPI 定数
– 実行しないとわからないけど確実
• phpinfo() の Server API 項目
– ただしこれは SAPI 名ではなく、SAPI の pretty name
$ /usr/sbin/php-fpm -v
PHP 7.2.2 (fpm-fcgi) (built: Feb 21 2018 08:31:14)
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.2, Copyright (c) 1999-2018, by Zend
Technologies
SAPI まとめ
• PHP 実行環境は同じバージョンでも複数の実体 (バ
イナリ) がある
• 実体の違いのほとんどは SAPI module の違い
• SAPI module の違いによって、PHP Script の実行
の仕方や、出力方法等が異なる
• ただし バイナリの違い !== SAPI の違い であるこ
とに注意
Zend Thread Safety (ZTS)
Q. SAPI module によって
起動した PHPは次に何をする?
A. リクエストを待つ
リクエスト
受付中
Q. SAPI module によって
起動した PHP は次に何をする?
A. リクエストを待つ
リクエスト
受付中
PHP の life cycle
SAPI Initialize
PHP Module Initialize
PHP Module Shutdown
(Waiting)
Request Initialize
Request Shutdown
PHP Script Execution
SAPI Shutdown
Request
(実行する PHP File を指定)
基本的にすべてのリソースは、リクエスト終了
(Request Shutdown)時 にリセットされる
PHP の life cycle
(前頁と同じ内容を別の書き方しただけ)
SAPI Initialize
SAPI Shutdown
PHP module Initialize (MINIT)
PHP module Shutdown (MSHUTDOWN)
Request Initialize (RINIT)
PHP Script Execution
Request Initialize (RSHUTDOWN)
Request Initialize (RINIT)
PHP Script Execution
Request Initialize (RSHUTDOWN)
t
i
m
e
PHP の基本的
な実行モデル
において、
一つのプロセ
スで、同時に
複数のリクエ
ストを処理す
ることはでき
ない
Prefork Model
(Multi Process)
SAPI Initialize
SAPI Shutdown
MINIT
MSHUTDOWN
RINIT
PHP Script
RSHUTDOWN
RINIT
PHP Script
RSHUTDOWN
MINIT
MSHUTDOWN
RINIT
PHP Script
RSHUTDOWN
MINIT
MSHUTDOWN
RINIT
PHP Script
RSHUTDOWN
・・・
process
リクエスト
を並列処理
するために
複数のプロ
セスを待機
させておく
Prefork Model
(Multi Process)
SAPI Initialize
SAPI Shutdown
MINIT
MSHUTDOWN
RINIT
PHP Script
RSHUTDOWN
RINIT
PHP Script
RSHUTDOWN
MINIT
MSHUTDOWN
RINIT
PHP Script
RSHUTDOWN
MINIT
MSHUTDOWN
RINIT
PHP Script
RSHUTDOWN
・・・
process
リクエスト
を並列処理
するために
複数のプロ
セスを待機
させておく
並行して起動する最大プロセス数
Apache httpd
(mpm:prefork) : MaxClients/MaxRequestWorkers ディレクティブ
cgi-fcgi (fcgi) : PHP_FCGI_CHILDREN 環境変数
php-fpm (1poolあたり) : pm.max_children 設定
Apache httpd
(mpm:prefork) : MaxRequestsPerChild / MaxConnectionsPerChild ディレクティブ
cgi-fcgi (fcgi) : PHP_FCGI_MAX_REQUESTS 環境変数
php-fpm : pm.max_requests 設定
1プロセスが処理する最大リクエスト数
一部のWebサーバによる
スレッドによるリクエスト処理に対応 (ZTS)
SAPI Initialize
SAPI Shutdown
MINIT
MSHUTDOWN
RINIT
PHP Script
RSHUTDOWN
RINIT
PHP Script
RSHUTDOWN
RINIT
PHP Script
RSHUTDOWN
RINIT
PHP Script
RSHUTDOWN
thread
単一のプロセス
に対し、異なる
スレッドでリク
エストを並列処
理することが可
能 (その代わり、
マルチスレッド
対応のコストが
かかる)
ZTS (Zend Thread Safety)
• Webサーバがスレッドでリクエストを処理するケースに備えて、
マルチスレッド環境下でもPHPの実行を可能にする特別対応のこと
– ZTS を有効にしてコンパイル => TS(Thread Safe) 版 PHP
– ZTS を無効にしてコンパイル => NTS (Non Thread Safe) 版 PHP
• ZTS は PHP Script 上で マルチスレッドプログラミングをサ
ポートするものではない
– PHP Script 上での マルチスレッドはやめとけ (by pauli)
• https://www.slideshare.net/jpauli/php-and-threads-zts#40
• TS版PHP でも、拡張が Thread Safe でないと破綻するので注意
ZTS が有効かどうかを知る方法
• php –v (CLI のみ!)
• PHP_ZTS 定数 (int(1): 有効 / int(0): 無効)
• phpinfo() の Thread Safety 項目 (enable / disable)
$ php –v
PHP 7.2.2 (cli) (built: Feb 21 2018 08:30:50) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.2, Copyright (c) 1999-2018, by Zend
Technologies
有効な場合は
(ZTS)
ZTS まとめ
• PHP 実行環境は同じバージョンでも複数の実体があり、
さらに、TS版(ZTS有効) と NTS版(ZTS無効) がある
• ZTS はスレッド化されたリクエストを処理するための機能
• PHP は 通常、 マルチプロセスによる並列化を想定している
ので、特別な理由がない限りは NTS版を利用しよう
• PHP Script での マルチスレッドプログラミングは避けた
ほうが良い (ほかの言語使おう)
Zend Engine
PHP’s Outline
Web
Server
or
Shell
SAPI
module
Zend Engine
Extensions
PHP Script
OS
PHP 全体像
• SAPI module や Zend Engine が Extension とし
て関数やクラスを登録
• PHP Script は登録された関数やクラスを介して、あ
るいは、 Zend Engine が言語構造として提供する機
能を介してのみ、外の世界とつながることができる
• 起点は常に SAPI module
• この大枠は、PHP5(ZE2) から PHP7(ZE3) になって
も変化していない
PHP の Source Code 階層
php-src
|- TSRM/ .......... (Thread Safe Resource Manager)
|- Zend/ .......... (Zend Engine 関連)
|- ext/ .......... (各種拡張)
|- opcache/
|- standard/
etc…
|- main/ .......... (SAPI に共通するロジック群)
|- sapi/ .......... (各種 SAPI module)
|- apache2handler/
|- cli/
etc…
|- win32/ .........(WIN32互換用)
Zend Directory の中身 (一部)
PHP Script Compiler
Lexer (zend_language_scanner.l)
Parser (zend_language_parser.y)
AST Generator (zend_ast.c)
Opcode Generator (zend_compile.c)
Memory Management
Memory Allocator (zend_alloc.c)
Cycles Collector (zend_gc.c)
Stream API
transport
filter
wrapper
Virtual Machine
Def (zend_vm_def.h,zend_vm_execute.skl)
Gen (zend_vm_gen.php)
Impl(zend_vm_execute.h,zend_execute.c,z
end_execute_API.c,zend_vm_opcodes.c,zend_op
code.c)
Built-in
Function
(zend_builtin_functions.c)
Class
(zend_closures.c,zend_gener
ators.c)
Interface
(zend_interfaces.c)
Exception
(zend_exceptions.c)
Data Structures
HashTable (zend_hash.c)
zend_string (zend_interfaces.c)
zend_list.c/zend_llist.c/zend_smart_str.c/zend_s
mart_string.c/zend_stack.c/zend_ts_hash.c
OOP
zend_inheritance.c,zen
d_objects.c,zend_objec
t_handlers.c,zend_obje
cts_API.c
Algorithm
Sort
(zend_sort.c)
ini File Parser
zend_ini.c,zend_ini_parse
r.y,zend_ini_scanner.l
Signal
Handling
zend_signal.c
Extension
Management
zend_extensions.c
Zend Engine とは
• 主に Zend ディレクトリに含まれるPHPのコア機能
– これが Zend Engine である という定義は(たぶん)ない
• PHP Script Compiler と PHP VM が主たる機能といえるだ
ろうが、それは他の機能抜きには成り立たないもの
– メモリ管理を行う Memory Manager / HashTable, zend_string といっ
たデータ構造 / 設定ファイルを読み込むための ini File Parser
– etc…
• + PHP の基本機能 (を構成する要素)
– 拡張管理 / PHP の組み込みクラス、関数、例外 / Stream API / Sort
Zend Engine 3
• 大枠は変わらず、個々の機能がブラッシュアップされた
– Compiler, VM, Memory Manager,zend_string, HashTable, sort,
object handler あたりの改良が主かなと
• 最新が PHP 7.2 で Version 3.2
– PHP 7.0 で Version 3.0, PHP 7.1 で Version 3.1
– PHP 5 の時は Version 2.0 – 2.6
• C言語上で ZEND_VERSION 定数として定義(Zend/zend.h)
– PHP Script からは zend_version() 関数で参照可能
• おそらく、バージョン番号にあまり意味はないのでは
Virtual Machine (PHP VM)
PHP Script は 中間コード に
変換されてから実行される
<?php
$name = "php";
echo "hello {$name}";
$_main: ; (lines=5, args=0, vars=1, tmps=2)
; (before optimizer)
; hello.php:1-5
L0 (3): ASSIGN CV0($name) string("php")
L1 (4): NOP
L2 (4): T2 = FAST_CONCAT string("hello ") CV0($name)
L3 (4): ECHO T2
L4 (5): RETURN int(1)
hello.php
php -d opcache.opt_debug_level=0x10000 -d opcache.enable_cli hello.php
1行1行が opcode という中間コード
(一連のopcode は op_array という塊で管理される)
phpdbg での出力例
(表現の仕方が異なるだけで同じもの)
<?php
$name = "php";
echo "hello {$name}";
function name: (null)
L1-5 {main}() hello.php - 5 ops
L3 #0 ASSIGN $name "php"
L4 #1 NOP
L4 #2 FAST_CONCAT "hello " $name ~1
L4 #3 ECHO ~1
L5 #4 RETURN<-1> 1
hello.php
phpdbg -p* hello.php
PHP
Compiler & VM
PHP Script
Opcode
Request
Output
Compiler
Lexing
Parsing
Compilation
VM
Execution
[INCLUDE_OR_EVAL]
requireやinclude,
eval を実行すると、そ
のタイミングでコンパイ
ルされる
(例えばオートロード時)
PHP Script
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
ECHO int(1)
INCLUDE_OR_EVAL (require) string("f.php")
INIT_FCALL_BY_NAME 0 string("foo")
DO_FCALL_BY_NAME
ECHO int(5)
RETURN int(1)
run.php
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
ECHO int(1)
INCLUDE_OR_EVAL (require) string("f.php")
INIT_FCALL_BY_NAME 0 string("foo")
DO_FCALL_BY_NAME
ECHO int(5)
RETURN int(1)
run.php
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
ECHO int(1)
INCLUDE_OR_EVAL (require) string("f.php")
INIT_FCALL_BY_NAME 0 string("foo")
DO_FCALL_BY_NAME
ECHO int(5)
RETURN int(1)
run.php
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
ECHO int(1)
INCLUDE_OR_EVAL (require) string("f.php")
INIT_FCALL_BY_NAME 0 string("foo")
DO_FCALL_BY_NAME
ECHO int(5)
RETURN int(1)
run.php
ECHO int(2)
NOP
ECHO int(3)
RETURN int(1)
ECHO int(4)
RETURN null
f.php
foo()
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
ECHO int(1)
INCLUDE_OR_EVAL (require) string("f.php")
INIT_FCALL_BY_NAME 0 string("foo")
DO_FCALL_BY_NAME
ECHO int(5)
RETURN int(1)
run.php
ECHO int(2)
NOP
ECHO int(3)
RETURN int(1)
ECHO int(4)
RETURN null
f.php
foo()
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
ECHO int(1)
INCLUDE_OR_EVAL (require) string("f.php")
INIT_FCALL_BY_NAME 0 string("foo")
DO_FCALL_BY_NAME
ECHO int(5)
RETURN int(1)
run.php
ECHO int(2)
NOP
ECHO int(3)
RETURN int(1)
ECHO int(4)
RETURN null
f.php
foo()
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
ECHO int(1)
INCLUDE_OR_EVAL (require) string("f.php")
INIT_FCALL_BY_NAME 0 string("foo")
DO_FCALL_BY_NAME
ECHO int(5)
RETURN int(1)
run.php
ECHO int(2)
NOP
ECHO int(3)
RETURN int(1)
ECHO int(4)
RETURN null
f.php
foo()
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
ECHO int(1)
INCLUDE_OR_EVAL (require) string("f.php")
INIT_FCALL_BY_NAME 0 string("foo")
DO_FCALL_BY_NAME
ECHO int(5)
RETURN int(1)
run.php
ECHO int(2)
NOP
ECHO int(3)
RETURN int(1)
ECHO int(4)
RETURN null
f.php
foo()
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
ECHO int(1)
INCLUDE_OR_EVAL (require) string("f.php")
INIT_FCALL_BY_NAME 0 string("foo")
DO_FCALL_BY_NAME
ECHO int(5)
RETURN int(1)
run.php
ECHO int(2)
NOP
ECHO int(3)
RETURN int(1)
ECHO int(4)
RETURN null
f.php
foo()
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
ECHO int(1)
INCLUDE_OR_EVAL (require) string("f.php")
INIT_FCALL_BY_NAME 0 string("foo")
DO_FCALL_BY_NAME
ECHO int(5)
RETURN int(1)
run.php
ECHO int(2)
NOP
ECHO int(3)
RETURN int(1)
ECHO int(4)
RETURN null
f.php
foo()
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
ECHO int(1)
INCLUDE_OR_EVAL (require) string("f.php")
INIT_FCALL_BY_NAME 0 string("foo")
DO_FCALL_BY_NAME
ECHO int(5)
RETURN int(1)
run.php
ECHO int(2)
NOP
ECHO int(3)
RETURN int(1)
ECHO int(4)
RETURN null
f.php
foo()
実行例
<?php
echo 1;
require 'f.php';
foo();
echo 5;
<?php
echo 2;
function foo() {
echo 4;
}
echo 3;
run.php
f.php
ECHO int(1)
INCLUDE_OR_EVAL (require) string("f.php")
INIT_FCALL_BY_NAME 0 string("foo")
DO_FCALL_BY_NAME
ECHO int(5)
RETURN int(1)
run.php
ECHO int(2)
NOP
ECHO int(3)
RETURN int(1)
ECHO int(4)
RETURN null
f.php
foo()
コンパイル時 と 実行時
• コンパイル時に解決されること
– 定数計算 (PHP>=7.0)
– ::class (クラスが存在するかどうか関係ない)
– __LINE__ 等のマジック定数 (ただし trait 内の __CLASS__
は実行時に決定)
– トップレベルの関数・クラス定義 (early binding)
• 実行時に解決されること
– その他すべて
early binding
<?php
func();
new Cls();
function func() {}
class Cls {}
定義よりも前に利用可能
コンパイル後、実行直前にトップレベルに定義されたクラスや関数を利用可
能に(名前付け)する処理
(クラスが継承、あるいは interface を実装している場合、このタイミング
でオートロードが走る)
early binding なし
<?php
func(); // Call to undefined function func()
new Cls(); // Class 'Cls' not found
if (1) {
function func() {}
class Cls {}
}
func(); // OK
new Cls(); // OK
定義がトップレベルではないの
で early binding されない
Compiler & VM
PHP Script
Opcode
Request
Output
Compiler
Lexing
Parsing
Compilation
VM
Execution
[INCLUDE_OR_EVAL]
requireやinclude,
eval を実行すると、そ
のタイミングでコンパイ
ルされる
(例えばオートロード時)
PHP Script
通常リクエスト終
了時に破棄される
(opcache はこれ
を再利用)
opcode
• PHP VM によって実行される命令セット
• 3アドレスコード
– 命令 + 引数1 + (引数2) + (戻り値格納先)
• CV:PHP Script 上の変数
• CONST: 定数(リテラル等)
• TMPVAR: PHPスクリプトには現れない一時的な変数
– ex: echo $a + $b + 3 の場合
• 命令の種類は増加傾向にある
– PHP5.6 150命令
– PHP7.0 168命令
– PHP7.1 185命令
– PHP7.2 196命令
• count や get_class 等の関数が命令 (ZEND_COUNT,
ZEND_GET_CLASS) となることで関数呼び出しのコスト減
ADD $a $b TMP1
ADD TMP1 3 TMP2
ECHO TMP2
(みたいな感じ)
(とはいえ、opcode は 内部では unsigned char なので、増えても 255までだと思う)
Threading Model
• threaded code と呼ばれるコードを生成する手段
– (multi-thread とは関係ない言葉であることに注意)
– PHP においては opcode の処理の仕方 (分岐方式)
• 4つの中から選択することができる (自前でPHPをコンパイルする場合)
– SWITCH (シンプル、ただし遅い)
– CALL (7.1 までのデフォルト)
– GOTO (速い、ただし一部の環境では動かない?)
– HYBRID (CALL をベースに GOTO も利用 7.2 からのデフォルト)
HYBRID はマイクロベンチで1.5倍、一般的なアプリケーション
でも数パーセント速度向上するとのこと
VM の生成方法
$ cd Zend
$ php zend_vm_gen.php --with-vm-kind=GOTO
zend_vm_opcodes.h generated successfully.
zend_vm_opcodes.c generated successfully.
zend_vm_execute.h generated successfully.
zend_vm_execute.sklzend_vm_def.h
VM の本体である zend_execute 関数が
ある (.h だけど実装が含まれる)
opcode の実装 テンプレート
zend_vm_execute.h
zend_vm_def.h
• 各 opcode の実装がここに記述されている
– ex:ZEND_JMP
• 実行する opcode の位置を変更するだけ
– ex:ZEND_CLONE
• object で __clone があれば呼び出し、なければ組み込みのコピー処
理を実行
• opcode によって実行コストが全く違う
– 単純に "opcode が少ない" === "速い" というわけではない
ZEND_VM_INTERRUPT
• 7.1 で導入された、割込み処理を低コストで実現する仕組み
– opcode を処理するたびに EG(vm_interrupt) を確認
– 割込み処理は非同期で EG(vm_interrupt) を 1 にする
– 割込みがあれば zend_interrupt_function や
zend_timeout が実行される
• signal や timeout (max_execution_time) で利用
• 割込み処理が早くなっただけでなく、タイムアウト時の挙動
が従来よりも安定している
Memory Allocator
&
Garbage Collector
PHP のメモリ管理
• PHP7になったときに大幅に変更 (高速化の主因)
– zval (変数の内部表現) の扱いとメモリレイアウト変更
• よりCPUキャッシュに乗りやすく
– アロケータ (Zend Memory Manager) の刷新
• 基本確保単位が変更
Segment:256KB(PHP5) -> Chunk:2MB(PHP7)
• GC が 参照カウンタ + 循環参照コレクタ というの
は変わらない
Zend Memory Manager
(Zend/zend_alloc.c)
• マネージャという名前だけど、実質的にはメモリアロケータ
• 通常割り当てられたメモリはすべてリクエスト終了時に破棄
– ZMM により、リクエストを越えてリークする可能性はない
– ただし、永続的な割り当ては管轄外(システムアロケータに委譲)
• メモリ解放漏れのチェック機構
– PHP Script の組み方によってリークするケースは循環参照のみ
– 拡張のメモリリークチェックに便利
• memory_limit の管理も仕事の一つ
– get_memory_usage(false) は 要求されたメモリ量
– get_memory_usage(true) は 実際に確保したメモリ量
Zend Memory Manager (PHP7)
<?php
$str = "PHP Script";
emalloc()
zend_mm_heap chunk chunk chunk
zend_mm_mmap()
mmap or VitualAlloc
(>=2MB)
page
page
page
page
OS
chunk
単位で確保slot
slot
slot
Zend Memory Manager (PHP5)
OS
<?php
$str = "PHP Script";
emalloc()
zend_mm_heap segment segment segment
win32 mmap_zeromalloc mmap_anon
storage_handler (ZEND_MM_MEM_TYPEで変更可)
(>=256KB / ZEND_MM_SEG_SIZEで変更可)
segment
単位で確保
block block block
廃止されたZMM関連の環境変数
(PHP5 では利用可能だったが PHP7では使えない)
• ZEND_MM_SEG_SIZE
– メモリ確保の基本単位(default:256KB)
– ある程度大きくすることで、メモリのフラグメントが防げるはず
• ZEND_MM_MEM_TYPE
– storage handler の指定
– 指定が無効な場合は、有効な名前を列挙してプログラム終了
• ZEND_MM_COMPACT (WIN32環境にのみ影響)
– メモリコンパクションを発動するサイズ (default:2MB)
– mmap系ではコンパクション実装がダミーになっているので意味がない
ZMM関連の環境変数 (PHP7)
• USE_ZEND_ALLOC
– PHP5 でも利用可能
– 0 を指定することで、emallocがシステムアロケータをそのまま利用す
ることになる
– Zend Memory Manager が無効になるので、memory_limit 等も使え
なくなる
• USE_ZEND_ALLOC_HUGE_PAGES (PHP>=7.0.6)
– MAP_HUGETLB マクロが有効な場合のみ利用可能 (実質的に!WIN32)
– 0 以外を指定することで、mmap のフラグに MAP_HUGETLB を付与
– (メモリを大量に使うプログラムで) Kernel の Huge Page が有効な
らば、TLB ミス軽減による高速化を期待できる
参照カウント
解放
'php'
(ref:1)
$a
'php'
(ref:2)
$a
$b
'php'
(ref:1)
$a
$b
'php'
(ref:0)$b
$a = 'php';
$b = $a;
unset($a);
unset($b);
生成
参照カウント(附記)
• メモリレイアウト変更により PHP7 でカウントの仕方が一部変更になった
が、参照カウント方式を利用していることは変わらない
そのため、循環参照コレクタも変わらず存在している
• 公式のドキュメント「参照カウント法の原理」 は PHP5 の内部をベースと
した解説であることに注意
– http://php.net/manual/ja/features.gc.refcounting-basics.php
– PHP7 においては、カウントの仕方が若干異なる
• The secret of PHP7's Performance を読むとPHP5とPHP7との違いが分
かりやすい (https://www.slideshare.net/laruence/the-secret-of-php7s-
performance#28 以降)
循環参照
$a = new stdClass();
$b = new stdClass();
$a->r = $b;
$b->r = $a;
unset($a);
unset($b);
$a
$b
stdClass(ref:1)
stdClass(ref:1)
$a
$b
stdClass(ref:2) r
stdClass(ref:2) r
$a
$b
stdClass(ref:1) r
stdClass(ref:2) r
$b
stdClass(ref:1) r
stdClass(ref:1) r
解放されない
循環参照コレクタ
(Zend/zend_gc.c)
• PHP + GC というコンテキストにおいて指すのはだいたいこれ
– 参照カウントも GC の一つではあるのだけど、 PHP Script 上でメモ
リリークする可能性があるのは循環参照のみだからだと思う
• PHP Script 上で実行を制御可能
– gc_enable / gc_diable / gc_enabled / gc_collect_cycles
– ちなみに gc_mm_caches (PHP>=7.0)は Zend Memory Manager にお
いて空き領域を再利用するための関数 (循環参照コレクタとは無関係)
• 循環参照コレクタの動作については y_uti さんの「PHPのGCの
話」が分かりやすい (https://www.slideshare.net/y-uti/php-gc)
循環参照コレクタの改善
• PHP7.3 で導入予定 (master マージ済み)
– https://github.com/php/php-src/pull/3165
• 大量に object がある場合のGC速度が大幅に改善された
– composer 速くなるかも
– 動作原理は大きく変わってない (と思う)
– ちゃんとは追えてない。詳しい人誰か
• ルートバッファ(リークする可能性のあるオブジェクトを記録したもの)の
最大数が(実質)撤廃
– 従来は 10,000 件を超えて記録できなくなるとリークしてた
– 初期 16,384件 (128KB) から、倍々あるいは 1MB 単位で最大 1GB まで増加
– 双方向リンクドリストからベクタに (これが高速化の主因?)
まとめ
• PHP プログラムの実行を支える仕組みの一部を解説しました
– PHP7.0 以降もさらに改善が進んでいる
• とはいえ、表面の解説をしただけで詳細はもっと深く、また
この資料で触れてない仕組みもまだまだたくさんあります
• これを機に PHP の内部に興味を持ってくれたら幸い
Any Question?
(blank)
Extensions
(Appendix.1)
関数は拡張に属している
• PHP Script から呼び出し可能な組み込みの関数は、すべてなにか
しらの拡張に属している
– 拡張の一覧は get_loaded_extensions 関数で取得可能
– 指定した拡張に属する関数の一覧は get_extension_funcs 関数で取
得可能
• Zend Engine が組み込みで提供する拡張
– Core Extension (strlen, define 等 Zend/zend_builtin_functions.c)
– Standard Extension (trim, constant 等 ext/standard/basic_functions.c)
– 他、 date, pcre, reflection, spl も
– (Core のみ特別に読み込んでいるが、この挙動はちょっと謎)
2種類の拡張
• Zend Extension
– Zend Engine を "拡張" する
– PHP Extension としても動作可能
• PHP Extension
– PHP Script を "拡張" する
– 内部的には PHP Module という名称
• 内部的な違いであって、利用者が意識することは少ない
– ini ファイルでの指定の仕方くらい
• Zend Extension は "zend_extension=xxx.so"
• PHP Extension は "extension=xxx.so"
外から見分ける方法
ライブラリの読み込みに利用するシンボルの違いで判別可能
$ nm ―D opcache.so | grep zend_extension_entry
000000000026a700 D zend_extension_entry
$ nm -D pdo.so | grep get_module
00000000000059b0 T get_module
Zend Extension の場合は必ず zend_extension_entry シンボル
が存在 (頭に _がつくケースもアリ)
PHP Extension の場合は zend_extension_entry はなく、
get_module シンボルが存在 (頭に _がつくケースもアリ)
Compile
(Appendix.2)
PHP Script
<?php
function hello ( $name ) {
echo "HELLO $name" ;
}
hello ( "php" ) ;
字句解析
(Zend/zend_language_scanner.l / re2c)
<?php
function hello ( $name ) {
echo "HELLO $name" ;
}
hello ( "php" ) ;
T_FUNCTION T_STRING ( ) {
}
T_ECHO
T_ENCAPSED_AND
_WHITESPACE ;
T_STRING ( ) ;
T_OPEN_TAG
T_VARIABLE
T_VARIABLE
T_VARIABLE" "
ひとつひとつがトークン
(意味を持つ最小の単位)
構文解析
(Zend/zend_language_parser.y / bison)
T_FUNCTION T_STRING ( ) {
}
T_ECHO T_ENCAPSED_AND_WHITESPACE ;
T_STRING ( ) ;
T_OPEN_TAG
T_VARIABLE
T_VARIABLE
function declaration
function call
AST構築
(Zend/zend_ast.c)
generated by
https://dooakitestapp.hero
kuapp.com/phpast/webapp/
Opcodeへの変換
(Zend/zend_compile.c)
$_main: ; (lines=5, args=0, vars=0, tmps=1)
; (before optimizer)
; hello.php:1-10
L0 (3): NOP
L1 (8): INIT_FCALL 1 112 string("hello")
L2 (8): SEND_VAL string("php") 1
L3 (8): DO_UCALL
L4 (10): RETURN int(1)
hello: ; (lines=5, args=1, vars=1, tmps=1)
; (before optimizer)
; hello.php:3-6
L0 (3): CV0($name) = RECV 1
L1 (4): NOP
L2 (4): T1 = FAST_CONCAT string("HELLO ") CV0($name)
L3 (4): ECHO T1
L4 (6): RETURN null
call hello()
declare hello()
$ php -d opcache.opt_debug_level=0x10000 -d opcache.enable_cli hello.php

More Related Content

What's hot

Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法について
Yuji Otani
 
Dockerイメージの理解とコンテナのライフサイクル
Dockerイメージの理解とコンテナのライフサイクルDockerイメージの理解とコンテナのライフサイクル
Dockerイメージの理解とコンテナのライフサイクル
Masahito Zembutsu
 
Phpをいじり倒す10の方法
Phpをいじり倒す10の方法Phpをいじり倒す10の方法
Phpをいじり倒す10の方法Moriyoshi Koizumi
 
雑なMySQLパフォーマンスチューニング
雑なMySQLパフォーマンスチューニング雑なMySQLパフォーマンスチューニング
雑なMySQLパフォーマンスチューニング
yoku0825
 
あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界
Yoshinori Nakanishi
 
Vacuum徹底解説
Vacuum徹底解説Vacuum徹底解説
Vacuum徹底解説
Masahiko Sawada
 
Where狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーWhere狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキー
yoku0825
 
ゼロからはじめるKVM超入門
ゼロからはじめるKVM超入門ゼロからはじめるKVM超入門
ゼロからはじめるKVM超入門
VirtualTech Japan Inc.
 
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
NTT DATA Technology & Innovation
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
土岐 孝平
 
PHP の GC の話
PHP の GC の話PHP の GC の話
PHP の GC の話
y-uti
 
Docker Compose 徹底解説
Docker Compose 徹底解説Docker Compose 徹底解説
Docker Compose 徹底解説
Masahito Zembutsu
 
MySQLerの7つ道具
MySQLerの7つ道具MySQLerの7つ道具
MySQLerの7つ道具
yoku0825
 
Twitterのsnowflakeについて
TwitterのsnowflakeについてTwitterのsnowflakeについて
Twitterのsnowflakeについてmoai kids
 
DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!
kwatch
 
MySQL 5.7にやられないためにおぼえておいてほしいこと
MySQL 5.7にやられないためにおぼえておいてほしいことMySQL 5.7にやられないためにおぼえておいてほしいこと
MySQL 5.7にやられないためにおぼえておいてほしいこと
yoku0825
 
Ethernetの受信処理
Ethernetの受信処理Ethernetの受信処理
Ethernetの受信処理
Takuya ASADA
 
なかったらINSERTしたいし、あるならロック取りたいやん?
なかったらINSERTしたいし、あるならロック取りたいやん?なかったらINSERTしたいし、あるならロック取りたいやん?
なかったらINSERTしたいし、あるならロック取りたいやん?
ichirin2501
 
PostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろうPostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろう
kasaharatt
 
hbstudy# 28 SELinux HandsOn 公開版
hbstudy# 28 SELinux HandsOn 公開版hbstudy# 28 SELinux HandsOn 公開版
hbstudy# 28 SELinux HandsOn 公開版
Hiroki Ishikawa
 

What's hot (20)

Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法について
 
Dockerイメージの理解とコンテナのライフサイクル
Dockerイメージの理解とコンテナのライフサイクルDockerイメージの理解とコンテナのライフサイクル
Dockerイメージの理解とコンテナのライフサイクル
 
Phpをいじり倒す10の方法
Phpをいじり倒す10の方法Phpをいじり倒す10の方法
Phpをいじり倒す10の方法
 
雑なMySQLパフォーマンスチューニング
雑なMySQLパフォーマンスチューニング雑なMySQLパフォーマンスチューニング
雑なMySQLパフォーマンスチューニング
 
あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界
 
Vacuum徹底解説
Vacuum徹底解説Vacuum徹底解説
Vacuum徹底解説
 
Where狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーWhere狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキー
 
ゼロからはじめるKVM超入門
ゼロからはじめるKVM超入門ゼロからはじめるKVM超入門
ゼロからはじめるKVM超入門
 
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
 
PHP の GC の話
PHP の GC の話PHP の GC の話
PHP の GC の話
 
Docker Compose 徹底解説
Docker Compose 徹底解説Docker Compose 徹底解説
Docker Compose 徹底解説
 
MySQLerの7つ道具
MySQLerの7つ道具MySQLerの7つ道具
MySQLerの7つ道具
 
Twitterのsnowflakeについて
TwitterのsnowflakeについてTwitterのsnowflakeについて
Twitterのsnowflakeについて
 
DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!
 
MySQL 5.7にやられないためにおぼえておいてほしいこと
MySQL 5.7にやられないためにおぼえておいてほしいことMySQL 5.7にやられないためにおぼえておいてほしいこと
MySQL 5.7にやられないためにおぼえておいてほしいこと
 
Ethernetの受信処理
Ethernetの受信処理Ethernetの受信処理
Ethernetの受信処理
 
なかったらINSERTしたいし、あるならロック取りたいやん?
なかったらINSERTしたいし、あるならロック取りたいやん?なかったらINSERTしたいし、あるならロック取りたいやん?
なかったらINSERTしたいし、あるならロック取りたいやん?
 
PostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろうPostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろう
 
hbstudy# 28 SELinux HandsOn 公開版
hbstudy# 28 SELinux HandsOn 公開版hbstudy# 28 SELinux HandsOn 公開版
hbstudy# 28 SELinux HandsOn 公開版
 

Similar to PHP と SAPI と ZendEngine3 と

php and sapi and zendengine2 and...
php and sapi and zendengine2 and...php and sapi and zendengine2 and...
php and sapi and zendengine2 and...do_aki
 
PHPの今とこれから2020
PHPの今とこれから2020PHPの今とこれから2020
PHPの今とこれから2020
Rui Hirokawa
 
Modern PHP Programming @ PFI Seminar
Modern PHP Programming @ PFI SeminarModern PHP Programming @ PFI Seminar
Modern PHP Programming @ PFI SeminarSotaro Karasawa
 
WTM53 phpフレームワーク いまさらcodeigniter
WTM53 phpフレームワーク いまさらcodeigniterWTM53 phpフレームワーク いまさらcodeigniter
WTM53 phpフレームワーク いまさらcodeigniterMasanori Oobayashi
 
スクリプト言語PHP攻略法
スクリプト言語PHP攻略法スクリプト言語PHP攻略法
スクリプト言語PHP攻略法
Rui Hirokawa
 
Php in ruby
Php in rubyPhp in ruby
Php in rubydo_aki
 
最新PHP事情 (2000年7月22日,PHPカンファレンス)
最新PHP事情 (2000年7月22日,PHPカンファレンス)最新PHP事情 (2000年7月22日,PHPカンファレンス)
最新PHP事情 (2000年7月22日,PHPカンファレンス)
Rui Hirokawa
 
PHPCON_TOKYO_2022_Bigginer.pptx
PHPCON_TOKYO_2022_Bigginer.pptxPHPCON_TOKYO_2022_Bigginer.pptx
PHPCON_TOKYO_2022_Bigginer.pptx
Hideo Kashioka
 
PHPの今とこれから2015
PHPの今とこれから2015PHPの今とこれから2015
PHPの今とこれから2015
Rui Hirokawa
 
WebAPIではじめるphp入門
WebAPIではじめるphp入門WebAPIではじめるphp入門
WebAPIではじめるphp入門Hiroaki Murayama
 
Webサーバのチューニング
WebサーバのチューニングWebサーバのチューニング
Webサーバのチューニング
Yu Komiya
 
第21回Creators MeetUp
第21回Creators MeetUp第21回Creators MeetUp
第21回Creators MeetUp
Kenichi Mukai
 
FuelPHP Osu Nagoya vol.1
FuelPHP Osu Nagoya vol.1FuelPHP Osu Nagoya vol.1
FuelPHP Osu Nagoya vol.1
Fumito Mizuno
 
Weeklycms20120218
Weeklycms20120218Weeklycms20120218
Weeklycms20120218
Yoshi Sakai
 
PHP in Java -Quercus- によるレガシーマイグレーション実例 #jjug_ccc #ccc_r12
PHP in Java -Quercus- によるレガシーマイグレーション実例 #jjug_ccc #ccc_r12PHP in Java -Quercus- によるレガシーマイグレーション実例 #jjug_ccc #ccc_r12
PHP in Java -Quercus- によるレガシーマイグレーション実例 #jjug_ccc #ccc_r12Ryuji Yamashita
 
2009 PHP初心者
2009 PHP初心者2009 PHP初心者
2009 PHP初心者
Hideo Kashioka
 
<第1回>Laravelハンズオンセミナー
<第1回>Laravelハンズオンセミナー<第1回>Laravelハンズオンセミナー
<第1回>Laravelハンズオンセミナー
Tatsuyoshi Mashiko
 
Hive undocumented feature
Hive undocumented featureHive undocumented feature
Hive undocumented featuretamtam180
 
PHPの今とこれから2016
PHPの今とこれから2016PHPの今とこれから2016
PHPの今とこれから2016
Rui Hirokawa
 

Similar to PHP と SAPI と ZendEngine3 と (20)

php and sapi and zendengine2 and...
php and sapi and zendengine2 and...php and sapi and zendengine2 and...
php and sapi and zendengine2 and...
 
PHPの今とこれから2020
PHPの今とこれから2020PHPの今とこれから2020
PHPの今とこれから2020
 
Modern PHP Programming @ PFI Seminar
Modern PHP Programming @ PFI SeminarModern PHP Programming @ PFI Seminar
Modern PHP Programming @ PFI Seminar
 
WTM53 phpフレームワーク いまさらcodeigniter
WTM53 phpフレームワーク いまさらcodeigniterWTM53 phpフレームワーク いまさらcodeigniter
WTM53 phpフレームワーク いまさらcodeigniter
 
スクリプト言語PHP攻略法
スクリプト言語PHP攻略法スクリプト言語PHP攻略法
スクリプト言語PHP攻略法
 
Php in ruby
Php in rubyPhp in ruby
Php in ruby
 
最新PHP事情 (2000年7月22日,PHPカンファレンス)
最新PHP事情 (2000年7月22日,PHPカンファレンス)最新PHP事情 (2000年7月22日,PHPカンファレンス)
最新PHP事情 (2000年7月22日,PHPカンファレンス)
 
PHPCON_TOKYO_2022_Bigginer.pptx
PHPCON_TOKYO_2022_Bigginer.pptxPHPCON_TOKYO_2022_Bigginer.pptx
PHPCON_TOKYO_2022_Bigginer.pptx
 
PHPの今とこれから2015
PHPの今とこれから2015PHPの今とこれから2015
PHPの今とこれから2015
 
WebAPIではじめるphp入門
WebAPIではじめるphp入門WebAPIではじめるphp入門
WebAPIではじめるphp入門
 
Webサーバのチューニング
WebサーバのチューニングWebサーバのチューニング
Webサーバのチューニング
 
第21回Creators MeetUp
第21回Creators MeetUp第21回Creators MeetUp
第21回Creators MeetUp
 
FuelPHP Osu Nagoya vol.1
FuelPHP Osu Nagoya vol.1FuelPHP Osu Nagoya vol.1
FuelPHP Osu Nagoya vol.1
 
PSGIへの誘い
PSGIへの誘いPSGIへの誘い
PSGIへの誘い
 
Weeklycms20120218
Weeklycms20120218Weeklycms20120218
Weeklycms20120218
 
PHP in Java -Quercus- によるレガシーマイグレーション実例 #jjug_ccc #ccc_r12
PHP in Java -Quercus- によるレガシーマイグレーション実例 #jjug_ccc #ccc_r12PHP in Java -Quercus- によるレガシーマイグレーション実例 #jjug_ccc #ccc_r12
PHP in Java -Quercus- によるレガシーマイグレーション実例 #jjug_ccc #ccc_r12
 
2009 PHP初心者
2009 PHP初心者2009 PHP初心者
2009 PHP初心者
 
<第1回>Laravelハンズオンセミナー
<第1回>Laravelハンズオンセミナー<第1回>Laravelハンズオンセミナー
<第1回>Laravelハンズオンセミナー
 
Hive undocumented feature
Hive undocumented featureHive undocumented feature
Hive undocumented feature
 
PHPの今とこれから2016
PHPの今とこれから2016PHPの今とこれから2016
PHPの今とこれから2016
 

More from do_aki

Tritonn から Elasticsearch への移行話
Tritonn から Elasticsearch への移行話Tritonn から Elasticsearch への移行話
Tritonn から Elasticsearch への移行話
do_aki
 
PHPとシグナル、その裏側
PHPとシグナル、その裏側PHPとシグナル、その裏側
PHPとシグナル、その裏側
do_aki
 
再考:列挙型
再考:列挙型再考:列挙型
再考:列挙型
do_aki
 
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かsignal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何か
do_aki
 
PHP AST 徹底解説(補遺)
PHP AST 徹底解説(補遺)PHP AST 徹底解説(補遺)
PHP AST 徹底解説(補遺)
do_aki
 
Writing php extensions in golang
Writing php extensions in golangWriting php extensions in golang
Writing php extensions in golang
do_aki
 
php7's ast
php7's astphp7's ast
php7's ast
do_aki
 
N対1 レプリケーション + Optimizer Hint
N対1 レプリケーション + Optimizer HintN対1 レプリケーション + Optimizer Hint
N対1 レプリケーション + Optimizer Hint
do_aki
 
20150212 プレゼンテーションzen
20150212 プレゼンテーションzen20150212 プレゼンテーションzen
20150212 プレゼンテーションzen
do_aki
 
MySQL Casual Talks 7 「N:1 レプリケーション ~進捗どうですか?~」
MySQL Casual Talks 7 「N:1 レプリケーション ~進捗どうですか?~」MySQL Casual Talks 7 「N:1 レプリケーション ~進捗どうですか?~」
MySQL Casual Talks 7 「N:1 レプリケーション ~進捗どうですか?~」
do_aki
 
20141017 introduce razor
20141017 introduce razor20141017 introduce razor
20141017 introduce razor
do_aki
 
20141011 mastering mysqlnd
20141011 mastering mysqlnd20141011 mastering mysqlnd
20141011 mastering mysqlnd
do_aki
 
php in ruby
php in rubyphp in ruby
php in ruby
do_aki
 
PHP から Groonga を使うにはこんなコードになるよ!
PHP から Groonga を使うにはこんなコードになるよ!PHP から Groonga を使うにはこんなコードになるよ!
PHP から Groonga を使うにはこんなコードになるよ!
do_aki
 
N:1 Replication meets MHA
N:1 Replication meets MHAN:1 Replication meets MHA
N:1 Replication meets MHAdo_aki
 
Php radomize
Php radomizePhp radomize
Php radomize
do_aki
 
セキュアそうでセキュアじゃない少しセキュアな気分になれるmysql_config_editor
セキュアそうでセキュアじゃない少しセキュアな気分になれるmysql_config_editorセキュアそうでセキュアじゃない少しセキュアな気分になれるmysql_config_editor
セキュアそうでセキュアじゃない少しセキュアな気分になれるmysql_config_editordo_aki
 
マスタN対スレーブ1レプリケーションの作り方 ~あれから~
マスタN対スレーブ1レプリケーションの作り方 ~あれから~マスタN対スレーブ1レプリケーションの作り方 ~あれから~
マスタN対スレーブ1レプリケーションの作り方 ~あれから~do_aki
 
Immortal
ImmortalImmortal
Immortaldo_aki
 
Excel is image viewer
Excel is image viewerExcel is image viewer
Excel is image viewer
do_aki
 

More from do_aki (20)

Tritonn から Elasticsearch への移行話
Tritonn から Elasticsearch への移行話Tritonn から Elasticsearch への移行話
Tritonn から Elasticsearch への移行話
 
PHPとシグナル、その裏側
PHPとシグナル、その裏側PHPとシグナル、その裏側
PHPとシグナル、その裏側
 
再考:列挙型
再考:列挙型再考:列挙型
再考:列挙型
 
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かsignal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何か
 
PHP AST 徹底解説(補遺)
PHP AST 徹底解説(補遺)PHP AST 徹底解説(補遺)
PHP AST 徹底解説(補遺)
 
Writing php extensions in golang
Writing php extensions in golangWriting php extensions in golang
Writing php extensions in golang
 
php7's ast
php7's astphp7's ast
php7's ast
 
N対1 レプリケーション + Optimizer Hint
N対1 レプリケーション + Optimizer HintN対1 レプリケーション + Optimizer Hint
N対1 レプリケーション + Optimizer Hint
 
20150212 プレゼンテーションzen
20150212 プレゼンテーションzen20150212 プレゼンテーションzen
20150212 プレゼンテーションzen
 
MySQL Casual Talks 7 「N:1 レプリケーション ~進捗どうですか?~」
MySQL Casual Talks 7 「N:1 レプリケーション ~進捗どうですか?~」MySQL Casual Talks 7 「N:1 レプリケーション ~進捗どうですか?~」
MySQL Casual Talks 7 「N:1 レプリケーション ~進捗どうですか?~」
 
20141017 introduce razor
20141017 introduce razor20141017 introduce razor
20141017 introduce razor
 
20141011 mastering mysqlnd
20141011 mastering mysqlnd20141011 mastering mysqlnd
20141011 mastering mysqlnd
 
php in ruby
php in rubyphp in ruby
php in ruby
 
PHP から Groonga を使うにはこんなコードになるよ!
PHP から Groonga を使うにはこんなコードになるよ!PHP から Groonga を使うにはこんなコードになるよ!
PHP から Groonga を使うにはこんなコードになるよ!
 
N:1 Replication meets MHA
N:1 Replication meets MHAN:1 Replication meets MHA
N:1 Replication meets MHA
 
Php radomize
Php radomizePhp radomize
Php radomize
 
セキュアそうでセキュアじゃない少しセキュアな気分になれるmysql_config_editor
セキュアそうでセキュアじゃない少しセキュアな気分になれるmysql_config_editorセキュアそうでセキュアじゃない少しセキュアな気分になれるmysql_config_editor
セキュアそうでセキュアじゃない少しセキュアな気分になれるmysql_config_editor
 
マスタN対スレーブ1レプリケーションの作り方 ~あれから~
マスタN対スレーブ1レプリケーションの作り方 ~あれから~マスタN対スレーブ1レプリケーションの作り方 ~あれから~
マスタN対スレーブ1レプリケーションの作り方 ~あれから~
 
Immortal
ImmortalImmortal
Immortal
 
Excel is image viewer
Excel is image viewerExcel is image viewer
Excel is image viewer
 

Recently uploaded

【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching
【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching
【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching
harmonylab
 
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LBカタログ
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LBカタログLoRaWAN 4チャンネル電流センサー・コンバーター CS01-LBカタログ
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LBカタログ
CRI Japan, Inc.
 
FIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdf
FIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdfFIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdf
FIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdf
FIDO Alliance
 
YugabyteDB適用に向けた取り組みと隠れた魅力 (DSS Asia 2024 発表資料)
YugabyteDB適用に向けた取り組みと隠れた魅力 (DSS Asia 2024 発表資料)YugabyteDB適用に向けた取り組みと隠れた魅力 (DSS Asia 2024 発表資料)
YugabyteDB適用に向けた取り組みと隠れた魅力 (DSS Asia 2024 発表資料)
NTT DATA Technology & Innovation
 
FIDO Alliance Osaka Seminar: CloudGate.pdf
FIDO Alliance Osaka Seminar: CloudGate.pdfFIDO Alliance Osaka Seminar: CloudGate.pdf
FIDO Alliance Osaka Seminar: CloudGate.pdf
FIDO Alliance
 
MPAなWebフレームワーク、Astroの紹介 (その2) 2024/05/24の勉強会で発表されたものです。
MPAなWebフレームワーク、Astroの紹介 (その2) 2024/05/24の勉強会で発表されたものです。MPAなWebフレームワーク、Astroの紹介 (その2) 2024/05/24の勉強会で発表されたものです。
MPAなWebフレームワーク、Astroの紹介 (その2) 2024/05/24の勉強会で発表されたものです。
iPride Co., Ltd.
 
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
Toru Tamaki
 
【AI論文解説】Consistency ModelとRectified Flow
【AI論文解説】Consistency ModelとRectified Flow【AI論文解説】Consistency ModelとRectified Flow
【AI論文解説】Consistency ModelとRectified Flow
Sony - Neural Network Libraries
 
FIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdf
FIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdfFIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdf
FIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdf
FIDO Alliance
 
論文紹介: Offline Q-Learning on diverse Multi-Task data both scales and generalizes
論文紹介: Offline Q-Learning on diverse Multi-Task data both scales and generalizes論文紹介: Offline Q-Learning on diverse Multi-Task data both scales and generalizes
論文紹介: Offline Q-Learning on diverse Multi-Task data both scales and generalizes
atsushi061452
 
2024年度_サイバーエージェント_新卒研修「データベースの歴史」.pptx
2024年度_サイバーエージェント_新卒研修「データベースの歴史」.pptx2024年度_サイバーエージェント_新卒研修「データベースの歴史」.pptx
2024年度_サイバーエージェント_新卒研修「データベースの歴史」.pptx
yassun7010
 
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
Matsushita Laboratory
 
CS集会#13_なるほどわからん通信技術 発表資料
CS集会#13_なるほどわからん通信技術 発表資料CS集会#13_なるほどわからん通信技術 発表資料
CS集会#13_なるほどわからん通信技術 発表資料
Yuuitirou528 default
 
単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...
単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...
単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...
Fukuoka Institute of Technology
 
FIDO Alliance Osaka Seminar: Welcome Slides.pdf
FIDO Alliance Osaka Seminar: Welcome Slides.pdfFIDO Alliance Osaka Seminar: Welcome Slides.pdf
FIDO Alliance Osaka Seminar: Welcome Slides.pdf
FIDO Alliance
 
FIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdf
FIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdfFIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdf
FIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdf
FIDO Alliance
 

Recently uploaded (16)

【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching
【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching
【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching
 
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LBカタログ
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LBカタログLoRaWAN 4チャンネル電流センサー・コンバーター CS01-LBカタログ
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LBカタログ
 
FIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdf
FIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdfFIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdf
FIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdf
 
YugabyteDB適用に向けた取り組みと隠れた魅力 (DSS Asia 2024 発表資料)
YugabyteDB適用に向けた取り組みと隠れた魅力 (DSS Asia 2024 発表資料)YugabyteDB適用に向けた取り組みと隠れた魅力 (DSS Asia 2024 発表資料)
YugabyteDB適用に向けた取り組みと隠れた魅力 (DSS Asia 2024 発表資料)
 
FIDO Alliance Osaka Seminar: CloudGate.pdf
FIDO Alliance Osaka Seminar: CloudGate.pdfFIDO Alliance Osaka Seminar: CloudGate.pdf
FIDO Alliance Osaka Seminar: CloudGate.pdf
 
MPAなWebフレームワーク、Astroの紹介 (その2) 2024/05/24の勉強会で発表されたものです。
MPAなWebフレームワーク、Astroの紹介 (その2) 2024/05/24の勉強会で発表されたものです。MPAなWebフレームワーク、Astroの紹介 (その2) 2024/05/24の勉強会で発表されたものです。
MPAなWebフレームワーク、Astroの紹介 (その2) 2024/05/24の勉強会で発表されたものです。
 
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
 
【AI論文解説】Consistency ModelとRectified Flow
【AI論文解説】Consistency ModelとRectified Flow【AI論文解説】Consistency ModelとRectified Flow
【AI論文解説】Consistency ModelとRectified Flow
 
FIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdf
FIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdfFIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdf
FIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdf
 
論文紹介: Offline Q-Learning on diverse Multi-Task data both scales and generalizes
論文紹介: Offline Q-Learning on diverse Multi-Task data both scales and generalizes論文紹介: Offline Q-Learning on diverse Multi-Task data both scales and generalizes
論文紹介: Offline Q-Learning on diverse Multi-Task data both scales and generalizes
 
2024年度_サイバーエージェント_新卒研修「データベースの歴史」.pptx
2024年度_サイバーエージェント_新卒研修「データベースの歴史」.pptx2024年度_サイバーエージェント_新卒研修「データベースの歴史」.pptx
2024年度_サイバーエージェント_新卒研修「データベースの歴史」.pptx
 
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
 
CS集会#13_なるほどわからん通信技術 発表資料
CS集会#13_なるほどわからん通信技術 発表資料CS集会#13_なるほどわからん通信技術 発表資料
CS集会#13_なるほどわからん通信技術 発表資料
 
単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...
単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...
単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...
 
FIDO Alliance Osaka Seminar: Welcome Slides.pdf
FIDO Alliance Osaka Seminar: Welcome Slides.pdfFIDO Alliance Osaka Seminar: Welcome Slides.pdf
FIDO Alliance Osaka Seminar: Welcome Slides.pdf
 
FIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdf
FIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdfFIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdf
FIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdf
 

PHP と SAPI と ZendEngine3 と

  • 1. PHP と SAPI と ZendEngine3 と 2018/03/09 PHPerKaigi 2018 do_aki
  • 3. はじめに <?php declare(strict_types=1); function hello( string $name):void { echo "hello {$name}"; } hello('php'); PHP スクリプト PHP 実行環境 PHP プログラムの実行 hello php
  • 4. はじめに <?php declare(strict_types=1); function hello( string $name):void { echo "hello {$name}"; } hello('php'); PHP スクリプト PHP 実行環境 PHP プログラムの実行 hello php トークする内容はここ
  • 5. 目次 1. Server API (SAPI) 2. Zend Thread Safety (ZTS) 3. Zend Engine 3.1 Virtual Machine (PHP VM) 3.2 Memory Allocator & Garbage Collector
  • 7. PHP プログラムの実行とは <?php declare(strict_types=1); function hello( string $name):void { echo "hello {$name}"; } hello('php'); PHP スクリプト (テキストファイル) PHP 実行環境 (ソフトウェア) 実行環境がなければ、 PHPスクリプトは ただのテキスト PHP プログラムの実行 hello php
  • 8. Webサーバと組み合わせて実行 (Web Server起動 時にロード済み) Web Server run PHP Script HTTP Request Web Server 組み込み型 Web Server CGI Protocol run PHP Script HTTP Request CGI型 起動して実行 Web Server FastCGI Protocol run PHP Script HTTP Request FastCGI型 起動済み
  • 9. PHP 単体で実行 Built-in WebServer (ex:php –S 127.0.0.1:3000) run PHP Script Webサーバと組み合わせずにスタンドアロンで動作 (Built-in Web Server は IO 多重化による、シングルプロセス実装なのでIO が Busy に なると並列処理できない。もし PHP Script 実行時にクラッシュすると、WebServer も巻 き込んで死ぬのであくまで開発用) HTTP Request Command Execution run PHP Script コマンド実行 (ex: php hoge.php) 起動して実行
  • 10. 複数ある PHP の実体(バイナリ) 主なファイル名 説明 [SAPI] libphp7.so php7apache2_4.dll Apache httpd のモジュールとして実行される PHP(ラ イブラリ) いわゆる mod_php [apache2handler] php-cgi php-cgi.exe いわゆる CGI版 PHP。CGIプロトコルだけでなくFastCGI プロトコルも実装した PHP (実行ファイル) [cgi-fcgi] php-fpm 高負荷環境に対応したプロセス管理を備えた、FastCGI プロトコル実装の PHP (実行ファイル) [fpm-fcgi] php php.exe php コマンド。 built in web server もこれで起動で きる (実行ファイル) [cli] [cli-server] phpdbg phpdbg.exe PHP の組み込みデバッガ (実行ファイル) [phpdbg] libphp7.so php7embed.lib 他のアプリケーションに組み込んで PHP を実行すること ができるようになるライブラリ [embed] lsphp LiteSpeed の LSAPI を実装した PHP (実行ファイル) [litespeed]
  • 11. SAPI と SAPI module PHP コア (Zend Engine) SAPI module SAPI Web Server or Shell apache2 handler or php-fpm or cli or etc… PHP Scri pt
  • 12. mod_php の場合 PHP コア (Zend Engine) SAPI module SAPIApache httpd apache2 handler PHP Scri pt
  • 13. php-fpm の場合 PHP コア (Zend Engine) SAPI module SAPI FastCGI supported Web Server (ex:nginx) fpm- fcgi PHP Scri pt
  • 14. php コマンド の場合 PHP コア (Zend Engine) SAPI module SAPIShell cli PHP Scri pt
  • 15. SAPI と SAPI module PHP コア (Zend Engine) SAPI module SAPI 様々な Web Server Web Server ごとの違 いを吸収 PHP Scri pt 異な る通 信方 式に 対応 PHPコアを起動するための ブートストラップでもある
  • 16. Server API (SAPI) • Web サーバごとの違いを吸収して、様々な Webサーバで PHP 実行環境を利用可能にする仕組み • これを実装した SAPI module が PHP 実行環境のブートス トラップとなる – 以前は Web サーバごとに数多く存在していたが、現在は Web サーバ - アプリケーションサーバ間のプロトコルが共通化して きたため少数 – 現在は、ほとんど動作方式の違いでしかない – SAPI module のことを指して SAPI と呼ぶこともある
  • 17. SAPI module (PHP7.2) • apache2handler (Apache 2.0 Handler) • cli (Command Line Interface) • cli-server (Built-in HTTP server) • phpdbg (phpdbg) • fpm-fcgi (FPM/FastCGI) • embed (PHP Embedded Library) • cgi-fcgi (CGI/FastCGI) • litespeed (LiteSpeed V6.11) ※括弧は pretty name
  • 18. SAPI module (PHP5.6) apache2handler (Apache 2.0 Handler) / cli (Command Line Interface) / cli-server (Built-in HTTP server) / phpdbg (phpdbg) / fpm-fcgi (FPM/FastCGI) / embed (PHP Embedded Library) / cgi-fcgi (CGI/FastCGI) / litespeed (LiteSpeed V6.10) ↑ PHP7 にもある/↓ PHP7で公式リポジトリからは削除された aolserver (AOLserver) / apache (Apache) / apache_hooks (Apache1) / apache2filter (Apache 2.0 Filter) / isapi (IIS) / caudium (Caudium) / Continuity (Continuity Server Enterprise Edition) / milter (Sendmail Milter SAPI) / nsapi (NSAPI) / phttpd (PHTTPD) / pi3web (PI3WEB) / roxen (Roxen) / thttpd (thttpd) / tux (tux) / webjames (WebJames)
  • 19. SAPI module の役割 • POSTやCookieデータの読み込み (read_post,read_cookie) • 環境変数の読み込み (getenv) • 出力制御 (ub_write,flush) • ヘッダ出力 (header_handler,send_headers, send_header) • 設定ファイル(php.ini)の扱い制御 – デフォルトパスの上書き (php_ini_path_override) – 読み込まない設定 (php_ini_ignore, php_ini_ignore_cwd) etc…
  • 20. SAPI module の役割ではないこと • ネットワーク接続 – socket 接続 – DB 接続 • ファイル入出力 – ファイルシステムへのアクセス • プロセス間通信 – signal – pipe (shell_exec) 多くは Zend Engine のストリームAPI (一部は拡張が直接制御)
  • 21. SAPI module による出力制御 <?php header("HTTP/1.0 418 I'm a tea pot"); echo "Hello World!"; Hello World! Hello World! • apache2handler (mod_php) の場合は apache httpd の関 数(ap_rwrite等) 呼び出し • fpm-fcgi (fpm) の場合は FastCGI protocol による socket への書き込み • cli の場合は write system call の呼び出し (header 出力は無視) PHP Script
  • 22. 設定ファイル(php.ini) のデフォルトパス • SAPI module ごとに異なる – コンパイル時に指定できる • ディストリビューションのパッケージで提供されているもの はだいたい一貫してる • コンパイル済みのバイナリを利用する場合、それぞれ異なる php.ini ファイルを参照する可能性があるので注意 – cli と php-fpm とで違う php.ini を見ているとかありうる
  • 23. 単一バイナリに 複数の SAPI module php(.exe) libphp.so php hoge.php php –S 127.0.0.1:3000 cli SAPI cli-server SAPI (--enable-cli) --enable-embed (unit SAPI) そのまま利用 一部利用して実装 [Any App] (embed SAPI)
  • 24. 同じ SAPI module で異なる動作 php-cgi lsphp php-cgi hoge.php php-cgi –b 127.0.0.1:9000 CGI として実行 FastCGI (待ち受け) (--enable-cgi) --with-litespeed cgi-fcgi SAPI (内部的には別処理) lsphp hoge.php lsphp –b 127.0.0.1:3000 ファイルを指定して実行 litespeed SAPI (内部的には別処理) LSAPI Server mode
  • 25. 利用している SAPI を知る方法 • (実行ファイルの場合) –v オプションを付けて実行 • php_sapi_name() の戻り値 あるいは PHP_SAPI 定数 – 実行しないとわからないけど確実 • phpinfo() の Server API 項目 – ただしこれは SAPI 名ではなく、SAPI の pretty name $ /usr/sbin/php-fpm -v PHP 7.2.2 (fpm-fcgi) (built: Feb 21 2018 08:31:14) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.2.2, Copyright (c) 1999-2018, by Zend Technologies
  • 26. SAPI まとめ • PHP 実行環境は同じバージョンでも複数の実体 (バ イナリ) がある • 実体の違いのほとんどは SAPI module の違い • SAPI module の違いによって、PHP Script の実行 の仕方や、出力方法等が異なる • ただし バイナリの違い !== SAPI の違い であるこ とに注意
  • 28. Q. SAPI module によって 起動した PHPは次に何をする? A. リクエストを待つ リクエスト 受付中
  • 29. Q. SAPI module によって 起動した PHP は次に何をする? A. リクエストを待つ リクエスト 受付中
  • 30. PHP の life cycle SAPI Initialize PHP Module Initialize PHP Module Shutdown (Waiting) Request Initialize Request Shutdown PHP Script Execution SAPI Shutdown Request (実行する PHP File を指定) 基本的にすべてのリソースは、リクエスト終了 (Request Shutdown)時 にリセットされる
  • 31. PHP の life cycle (前頁と同じ内容を別の書き方しただけ) SAPI Initialize SAPI Shutdown PHP module Initialize (MINIT) PHP module Shutdown (MSHUTDOWN) Request Initialize (RINIT) PHP Script Execution Request Initialize (RSHUTDOWN) Request Initialize (RINIT) PHP Script Execution Request Initialize (RSHUTDOWN) t i m e PHP の基本的 な実行モデル において、 一つのプロセ スで、同時に 複数のリクエ ストを処理す ることはでき ない
  • 32. Prefork Model (Multi Process) SAPI Initialize SAPI Shutdown MINIT MSHUTDOWN RINIT PHP Script RSHUTDOWN RINIT PHP Script RSHUTDOWN MINIT MSHUTDOWN RINIT PHP Script RSHUTDOWN MINIT MSHUTDOWN RINIT PHP Script RSHUTDOWN ・・・ process リクエスト を並列処理 するために 複数のプロ セスを待機 させておく
  • 33. Prefork Model (Multi Process) SAPI Initialize SAPI Shutdown MINIT MSHUTDOWN RINIT PHP Script RSHUTDOWN RINIT PHP Script RSHUTDOWN MINIT MSHUTDOWN RINIT PHP Script RSHUTDOWN MINIT MSHUTDOWN RINIT PHP Script RSHUTDOWN ・・・ process リクエスト を並列処理 するために 複数のプロ セスを待機 させておく 並行して起動する最大プロセス数 Apache httpd (mpm:prefork) : MaxClients/MaxRequestWorkers ディレクティブ cgi-fcgi (fcgi) : PHP_FCGI_CHILDREN 環境変数 php-fpm (1poolあたり) : pm.max_children 設定 Apache httpd (mpm:prefork) : MaxRequestsPerChild / MaxConnectionsPerChild ディレクティブ cgi-fcgi (fcgi) : PHP_FCGI_MAX_REQUESTS 環境変数 php-fpm : pm.max_requests 設定 1プロセスが処理する最大リクエスト数
  • 34. 一部のWebサーバによる スレッドによるリクエスト処理に対応 (ZTS) SAPI Initialize SAPI Shutdown MINIT MSHUTDOWN RINIT PHP Script RSHUTDOWN RINIT PHP Script RSHUTDOWN RINIT PHP Script RSHUTDOWN RINIT PHP Script RSHUTDOWN thread 単一のプロセス に対し、異なる スレッドでリク エストを並列処 理することが可 能 (その代わり、 マルチスレッド 対応のコストが かかる)
  • 35. ZTS (Zend Thread Safety) • Webサーバがスレッドでリクエストを処理するケースに備えて、 マルチスレッド環境下でもPHPの実行を可能にする特別対応のこと – ZTS を有効にしてコンパイル => TS(Thread Safe) 版 PHP – ZTS を無効にしてコンパイル => NTS (Non Thread Safe) 版 PHP • ZTS は PHP Script 上で マルチスレッドプログラミングをサ ポートするものではない – PHP Script 上での マルチスレッドはやめとけ (by pauli) • https://www.slideshare.net/jpauli/php-and-threads-zts#40 • TS版PHP でも、拡張が Thread Safe でないと破綻するので注意
  • 36. ZTS が有効かどうかを知る方法 • php –v (CLI のみ!) • PHP_ZTS 定数 (int(1): 有効 / int(0): 無効) • phpinfo() の Thread Safety 項目 (enable / disable) $ php –v PHP 7.2.2 (cli) (built: Feb 21 2018 08:30:50) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.2.2, Copyright (c) 1999-2018, by Zend Technologies 有効な場合は (ZTS)
  • 37. ZTS まとめ • PHP 実行環境は同じバージョンでも複数の実体があり、 さらに、TS版(ZTS有効) と NTS版(ZTS無効) がある • ZTS はスレッド化されたリクエストを処理するための機能 • PHP は 通常、 マルチプロセスによる並列化を想定している ので、特別な理由がない限りは NTS版を利用しよう • PHP Script での マルチスレッドプログラミングは避けた ほうが良い (ほかの言語使おう)
  • 40. PHP 全体像 • SAPI module や Zend Engine が Extension とし て関数やクラスを登録 • PHP Script は登録された関数やクラスを介して、あ るいは、 Zend Engine が言語構造として提供する機 能を介してのみ、外の世界とつながることができる • 起点は常に SAPI module • この大枠は、PHP5(ZE2) から PHP7(ZE3) になって も変化していない
  • 41. PHP の Source Code 階層 php-src |- TSRM/ .......... (Thread Safe Resource Manager) |- Zend/ .......... (Zend Engine 関連) |- ext/ .......... (各種拡張) |- opcache/ |- standard/ etc… |- main/ .......... (SAPI に共通するロジック群) |- sapi/ .......... (各種 SAPI module) |- apache2handler/ |- cli/ etc… |- win32/ .........(WIN32互換用)
  • 42. Zend Directory の中身 (一部) PHP Script Compiler Lexer (zend_language_scanner.l) Parser (zend_language_parser.y) AST Generator (zend_ast.c) Opcode Generator (zend_compile.c) Memory Management Memory Allocator (zend_alloc.c) Cycles Collector (zend_gc.c) Stream API transport filter wrapper Virtual Machine Def (zend_vm_def.h,zend_vm_execute.skl) Gen (zend_vm_gen.php) Impl(zend_vm_execute.h,zend_execute.c,z end_execute_API.c,zend_vm_opcodes.c,zend_op code.c) Built-in Function (zend_builtin_functions.c) Class (zend_closures.c,zend_gener ators.c) Interface (zend_interfaces.c) Exception (zend_exceptions.c) Data Structures HashTable (zend_hash.c) zend_string (zend_interfaces.c) zend_list.c/zend_llist.c/zend_smart_str.c/zend_s mart_string.c/zend_stack.c/zend_ts_hash.c OOP zend_inheritance.c,zen d_objects.c,zend_objec t_handlers.c,zend_obje cts_API.c Algorithm Sort (zend_sort.c) ini File Parser zend_ini.c,zend_ini_parse r.y,zend_ini_scanner.l Signal Handling zend_signal.c Extension Management zend_extensions.c
  • 43. Zend Engine とは • 主に Zend ディレクトリに含まれるPHPのコア機能 – これが Zend Engine である という定義は(たぶん)ない • PHP Script Compiler と PHP VM が主たる機能といえるだ ろうが、それは他の機能抜きには成り立たないもの – メモリ管理を行う Memory Manager / HashTable, zend_string といっ たデータ構造 / 設定ファイルを読み込むための ini File Parser – etc… • + PHP の基本機能 (を構成する要素) – 拡張管理 / PHP の組み込みクラス、関数、例外 / Stream API / Sort
  • 44. Zend Engine 3 • 大枠は変わらず、個々の機能がブラッシュアップされた – Compiler, VM, Memory Manager,zend_string, HashTable, sort, object handler あたりの改良が主かなと • 最新が PHP 7.2 で Version 3.2 – PHP 7.0 で Version 3.0, PHP 7.1 で Version 3.1 – PHP 5 の時は Version 2.0 – 2.6 • C言語上で ZEND_VERSION 定数として定義(Zend/zend.h) – PHP Script からは zend_version() 関数で参照可能 • おそらく、バージョン番号にあまり意味はないのでは
  • 46. PHP Script は 中間コード に 変換されてから実行される <?php $name = "php"; echo "hello {$name}"; $_main: ; (lines=5, args=0, vars=1, tmps=2) ; (before optimizer) ; hello.php:1-5 L0 (3): ASSIGN CV0($name) string("php") L1 (4): NOP L2 (4): T2 = FAST_CONCAT string("hello ") CV0($name) L3 (4): ECHO T2 L4 (5): RETURN int(1) hello.php php -d opcache.opt_debug_level=0x10000 -d opcache.enable_cli hello.php 1行1行が opcode という中間コード (一連のopcode は op_array という塊で管理される)
  • 47. phpdbg での出力例 (表現の仕方が異なるだけで同じもの) <?php $name = "php"; echo "hello {$name}"; function name: (null) L1-5 {main}() hello.php - 5 ops L3 #0 ASSIGN $name "php" L4 #1 NOP L4 #2 FAST_CONCAT "hello " $name ~1 L4 #3 ECHO ~1 L5 #4 RETURN<-1> 1 hello.php phpdbg -p* hello.php
  • 48. PHP Compiler & VM PHP Script Opcode Request Output Compiler Lexing Parsing Compilation VM Execution [INCLUDE_OR_EVAL] requireやinclude, eval を実行すると、そ のタイミングでコンパイ ルされる (例えばオートロード時) PHP Script
  • 49. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php
  • 50. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php ECHO int(1) INCLUDE_OR_EVAL (require) string("f.php") INIT_FCALL_BY_NAME 0 string("foo") DO_FCALL_BY_NAME ECHO int(5) RETURN int(1) run.php
  • 51. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php ECHO int(1) INCLUDE_OR_EVAL (require) string("f.php") INIT_FCALL_BY_NAME 0 string("foo") DO_FCALL_BY_NAME ECHO int(5) RETURN int(1) run.php
  • 52. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php ECHO int(1) INCLUDE_OR_EVAL (require) string("f.php") INIT_FCALL_BY_NAME 0 string("foo") DO_FCALL_BY_NAME ECHO int(5) RETURN int(1) run.php
  • 53. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php ECHO int(1) INCLUDE_OR_EVAL (require) string("f.php") INIT_FCALL_BY_NAME 0 string("foo") DO_FCALL_BY_NAME ECHO int(5) RETURN int(1) run.php ECHO int(2) NOP ECHO int(3) RETURN int(1) ECHO int(4) RETURN null f.php foo()
  • 54. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php ECHO int(1) INCLUDE_OR_EVAL (require) string("f.php") INIT_FCALL_BY_NAME 0 string("foo") DO_FCALL_BY_NAME ECHO int(5) RETURN int(1) run.php ECHO int(2) NOP ECHO int(3) RETURN int(1) ECHO int(4) RETURN null f.php foo()
  • 55. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php ECHO int(1) INCLUDE_OR_EVAL (require) string("f.php") INIT_FCALL_BY_NAME 0 string("foo") DO_FCALL_BY_NAME ECHO int(5) RETURN int(1) run.php ECHO int(2) NOP ECHO int(3) RETURN int(1) ECHO int(4) RETURN null f.php foo()
  • 56. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php ECHO int(1) INCLUDE_OR_EVAL (require) string("f.php") INIT_FCALL_BY_NAME 0 string("foo") DO_FCALL_BY_NAME ECHO int(5) RETURN int(1) run.php ECHO int(2) NOP ECHO int(3) RETURN int(1) ECHO int(4) RETURN null f.php foo()
  • 57. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php ECHO int(1) INCLUDE_OR_EVAL (require) string("f.php") INIT_FCALL_BY_NAME 0 string("foo") DO_FCALL_BY_NAME ECHO int(5) RETURN int(1) run.php ECHO int(2) NOP ECHO int(3) RETURN int(1) ECHO int(4) RETURN null f.php foo()
  • 58. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php ECHO int(1) INCLUDE_OR_EVAL (require) string("f.php") INIT_FCALL_BY_NAME 0 string("foo") DO_FCALL_BY_NAME ECHO int(5) RETURN int(1) run.php ECHO int(2) NOP ECHO int(3) RETURN int(1) ECHO int(4) RETURN null f.php foo()
  • 59. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php ECHO int(1) INCLUDE_OR_EVAL (require) string("f.php") INIT_FCALL_BY_NAME 0 string("foo") DO_FCALL_BY_NAME ECHO int(5) RETURN int(1) run.php ECHO int(2) NOP ECHO int(3) RETURN int(1) ECHO int(4) RETURN null f.php foo()
  • 60. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php ECHO int(1) INCLUDE_OR_EVAL (require) string("f.php") INIT_FCALL_BY_NAME 0 string("foo") DO_FCALL_BY_NAME ECHO int(5) RETURN int(1) run.php ECHO int(2) NOP ECHO int(3) RETURN int(1) ECHO int(4) RETURN null f.php foo()
  • 61. 実行例 <?php echo 1; require 'f.php'; foo(); echo 5; <?php echo 2; function foo() { echo 4; } echo 3; run.php f.php ECHO int(1) INCLUDE_OR_EVAL (require) string("f.php") INIT_FCALL_BY_NAME 0 string("foo") DO_FCALL_BY_NAME ECHO int(5) RETURN int(1) run.php ECHO int(2) NOP ECHO int(3) RETURN int(1) ECHO int(4) RETURN null f.php foo()
  • 62. コンパイル時 と 実行時 • コンパイル時に解決されること – 定数計算 (PHP>=7.0) – ::class (クラスが存在するかどうか関係ない) – __LINE__ 等のマジック定数 (ただし trait 内の __CLASS__ は実行時に決定) – トップレベルの関数・クラス定義 (early binding) • 実行時に解決されること – その他すべて
  • 63. early binding <?php func(); new Cls(); function func() {} class Cls {} 定義よりも前に利用可能 コンパイル後、実行直前にトップレベルに定義されたクラスや関数を利用可 能に(名前付け)する処理 (クラスが継承、あるいは interface を実装している場合、このタイミング でオートロードが走る)
  • 64. early binding なし <?php func(); // Call to undefined function func() new Cls(); // Class 'Cls' not found if (1) { function func() {} class Cls {} } func(); // OK new Cls(); // OK 定義がトップレベルではないの で early binding されない
  • 65. Compiler & VM PHP Script Opcode Request Output Compiler Lexing Parsing Compilation VM Execution [INCLUDE_OR_EVAL] requireやinclude, eval を実行すると、そ のタイミングでコンパイ ルされる (例えばオートロード時) PHP Script 通常リクエスト終 了時に破棄される (opcache はこれ を再利用)
  • 66. opcode • PHP VM によって実行される命令セット • 3アドレスコード – 命令 + 引数1 + (引数2) + (戻り値格納先) • CV:PHP Script 上の変数 • CONST: 定数(リテラル等) • TMPVAR: PHPスクリプトには現れない一時的な変数 – ex: echo $a + $b + 3 の場合 • 命令の種類は増加傾向にある – PHP5.6 150命令 – PHP7.0 168命令 – PHP7.1 185命令 – PHP7.2 196命令 • count や get_class 等の関数が命令 (ZEND_COUNT, ZEND_GET_CLASS) となることで関数呼び出しのコスト減 ADD $a $b TMP1 ADD TMP1 3 TMP2 ECHO TMP2 (みたいな感じ) (とはいえ、opcode は 内部では unsigned char なので、増えても 255までだと思う)
  • 67. Threading Model • threaded code と呼ばれるコードを生成する手段 – (multi-thread とは関係ない言葉であることに注意) – PHP においては opcode の処理の仕方 (分岐方式) • 4つの中から選択することができる (自前でPHPをコンパイルする場合) – SWITCH (シンプル、ただし遅い) – CALL (7.1 までのデフォルト) – GOTO (速い、ただし一部の環境では動かない?) – HYBRID (CALL をベースに GOTO も利用 7.2 からのデフォルト) HYBRID はマイクロベンチで1.5倍、一般的なアプリケーション でも数パーセント速度向上するとのこと
  • 68. VM の生成方法 $ cd Zend $ php zend_vm_gen.php --with-vm-kind=GOTO zend_vm_opcodes.h generated successfully. zend_vm_opcodes.c generated successfully. zend_vm_execute.h generated successfully. zend_vm_execute.sklzend_vm_def.h VM の本体である zend_execute 関数が ある (.h だけど実装が含まれる) opcode の実装 テンプレート zend_vm_execute.h
  • 69. zend_vm_def.h • 各 opcode の実装がここに記述されている – ex:ZEND_JMP • 実行する opcode の位置を変更するだけ – ex:ZEND_CLONE • object で __clone があれば呼び出し、なければ組み込みのコピー処 理を実行 • opcode によって実行コストが全く違う – 単純に "opcode が少ない" === "速い" というわけではない
  • 70. ZEND_VM_INTERRUPT • 7.1 で導入された、割込み処理を低コストで実現する仕組み – opcode を処理するたびに EG(vm_interrupt) を確認 – 割込み処理は非同期で EG(vm_interrupt) を 1 にする – 割込みがあれば zend_interrupt_function や zend_timeout が実行される • signal や timeout (max_execution_time) で利用 • 割込み処理が早くなっただけでなく、タイムアウト時の挙動 が従来よりも安定している
  • 72. PHP のメモリ管理 • PHP7になったときに大幅に変更 (高速化の主因) – zval (変数の内部表現) の扱いとメモリレイアウト変更 • よりCPUキャッシュに乗りやすく – アロケータ (Zend Memory Manager) の刷新 • 基本確保単位が変更 Segment:256KB(PHP5) -> Chunk:2MB(PHP7) • GC が 参照カウンタ + 循環参照コレクタ というの は変わらない
  • 73. Zend Memory Manager (Zend/zend_alloc.c) • マネージャという名前だけど、実質的にはメモリアロケータ • 通常割り当てられたメモリはすべてリクエスト終了時に破棄 – ZMM により、リクエストを越えてリークする可能性はない – ただし、永続的な割り当ては管轄外(システムアロケータに委譲) • メモリ解放漏れのチェック機構 – PHP Script の組み方によってリークするケースは循環参照のみ – 拡張のメモリリークチェックに便利 • memory_limit の管理も仕事の一つ – get_memory_usage(false) は 要求されたメモリ量 – get_memory_usage(true) は 実際に確保したメモリ量
  • 74. Zend Memory Manager (PHP7) <?php $str = "PHP Script"; emalloc() zend_mm_heap chunk chunk chunk zend_mm_mmap() mmap or VitualAlloc (>=2MB) page page page page OS chunk 単位で確保slot slot slot
  • 75. Zend Memory Manager (PHP5) OS <?php $str = "PHP Script"; emalloc() zend_mm_heap segment segment segment win32 mmap_zeromalloc mmap_anon storage_handler (ZEND_MM_MEM_TYPEで変更可) (>=256KB / ZEND_MM_SEG_SIZEで変更可) segment 単位で確保 block block block
  • 76. 廃止されたZMM関連の環境変数 (PHP5 では利用可能だったが PHP7では使えない) • ZEND_MM_SEG_SIZE – メモリ確保の基本単位(default:256KB) – ある程度大きくすることで、メモリのフラグメントが防げるはず • ZEND_MM_MEM_TYPE – storage handler の指定 – 指定が無効な場合は、有効な名前を列挙してプログラム終了 • ZEND_MM_COMPACT (WIN32環境にのみ影響) – メモリコンパクションを発動するサイズ (default:2MB) – mmap系ではコンパクション実装がダミーになっているので意味がない
  • 77. ZMM関連の環境変数 (PHP7) • USE_ZEND_ALLOC – PHP5 でも利用可能 – 0 を指定することで、emallocがシステムアロケータをそのまま利用す ることになる – Zend Memory Manager が無効になるので、memory_limit 等も使え なくなる • USE_ZEND_ALLOC_HUGE_PAGES (PHP>=7.0.6) – MAP_HUGETLB マクロが有効な場合のみ利用可能 (実質的に!WIN32) – 0 以外を指定することで、mmap のフラグに MAP_HUGETLB を付与 – (メモリを大量に使うプログラムで) Kernel の Huge Page が有効な らば、TLB ミス軽減による高速化を期待できる
  • 79. 参照カウント(附記) • メモリレイアウト変更により PHP7 でカウントの仕方が一部変更になった が、参照カウント方式を利用していることは変わらない そのため、循環参照コレクタも変わらず存在している • 公式のドキュメント「参照カウント法の原理」 は PHP5 の内部をベースと した解説であることに注意 – http://php.net/manual/ja/features.gc.refcounting-basics.php – PHP7 においては、カウントの仕方が若干異なる • The secret of PHP7's Performance を読むとPHP5とPHP7との違いが分 かりやすい (https://www.slideshare.net/laruence/the-secret-of-php7s- performance#28 以降)
  • 80. 循環参照 $a = new stdClass(); $b = new stdClass(); $a->r = $b; $b->r = $a; unset($a); unset($b); $a $b stdClass(ref:1) stdClass(ref:1) $a $b stdClass(ref:2) r stdClass(ref:2) r $a $b stdClass(ref:1) r stdClass(ref:2) r $b stdClass(ref:1) r stdClass(ref:1) r 解放されない
  • 81. 循環参照コレクタ (Zend/zend_gc.c) • PHP + GC というコンテキストにおいて指すのはだいたいこれ – 参照カウントも GC の一つではあるのだけど、 PHP Script 上でメモ リリークする可能性があるのは循環参照のみだからだと思う • PHP Script 上で実行を制御可能 – gc_enable / gc_diable / gc_enabled / gc_collect_cycles – ちなみに gc_mm_caches (PHP>=7.0)は Zend Memory Manager にお いて空き領域を再利用するための関数 (循環参照コレクタとは無関係) • 循環参照コレクタの動作については y_uti さんの「PHPのGCの 話」が分かりやすい (https://www.slideshare.net/y-uti/php-gc)
  • 82. 循環参照コレクタの改善 • PHP7.3 で導入予定 (master マージ済み) – https://github.com/php/php-src/pull/3165 • 大量に object がある場合のGC速度が大幅に改善された – composer 速くなるかも – 動作原理は大きく変わってない (と思う) – ちゃんとは追えてない。詳しい人誰か • ルートバッファ(リークする可能性のあるオブジェクトを記録したもの)の 最大数が(実質)撤廃 – 従来は 10,000 件を超えて記録できなくなるとリークしてた – 初期 16,384件 (128KB) から、倍々あるいは 1MB 単位で最大 1GB まで増加 – 双方向リンクドリストからベクタに (これが高速化の主因?)
  • 83. まとめ • PHP プログラムの実行を支える仕組みの一部を解説しました – PHP7.0 以降もさらに改善が進んでいる • とはいえ、表面の解説をしただけで詳細はもっと深く、また この資料で触れてない仕組みもまだまだたくさんあります • これを機に PHP の内部に興味を持ってくれたら幸い
  • 87. 関数は拡張に属している • PHP Script から呼び出し可能な組み込みの関数は、すべてなにか しらの拡張に属している – 拡張の一覧は get_loaded_extensions 関数で取得可能 – 指定した拡張に属する関数の一覧は get_extension_funcs 関数で取 得可能 • Zend Engine が組み込みで提供する拡張 – Core Extension (strlen, define 等 Zend/zend_builtin_functions.c) – Standard Extension (trim, constant 等 ext/standard/basic_functions.c) – 他、 date, pcre, reflection, spl も – (Core のみ特別に読み込んでいるが、この挙動はちょっと謎)
  • 88. 2種類の拡張 • Zend Extension – Zend Engine を "拡張" する – PHP Extension としても動作可能 • PHP Extension – PHP Script を "拡張" する – 内部的には PHP Module という名称 • 内部的な違いであって、利用者が意識することは少ない – ini ファイルでの指定の仕方くらい • Zend Extension は "zend_extension=xxx.so" • PHP Extension は "extension=xxx.so"
  • 89. 外から見分ける方法 ライブラリの読み込みに利用するシンボルの違いで判別可能 $ nm ―D opcache.so | grep zend_extension_entry 000000000026a700 D zend_extension_entry $ nm -D pdo.so | grep get_module 00000000000059b0 T get_module Zend Extension の場合は必ず zend_extension_entry シンボル が存在 (頭に _がつくケースもアリ) PHP Extension の場合は zend_extension_entry はなく、 get_module シンボルが存在 (頭に _がつくケースもアリ)
  • 91. PHP Script <?php function hello ( $name ) { echo "HELLO $name" ; } hello ( "php" ) ;
  • 92. 字句解析 (Zend/zend_language_scanner.l / re2c) <?php function hello ( $name ) { echo "HELLO $name" ; } hello ( "php" ) ; T_FUNCTION T_STRING ( ) { } T_ECHO T_ENCAPSED_AND _WHITESPACE ; T_STRING ( ) ; T_OPEN_TAG T_VARIABLE T_VARIABLE T_VARIABLE" " ひとつひとつがトークン (意味を持つ最小の単位)
  • 93. 構文解析 (Zend/zend_language_parser.y / bison) T_FUNCTION T_STRING ( ) { } T_ECHO T_ENCAPSED_AND_WHITESPACE ; T_STRING ( ) ; T_OPEN_TAG T_VARIABLE T_VARIABLE function declaration function call
  • 95. Opcodeへの変換 (Zend/zend_compile.c) $_main: ; (lines=5, args=0, vars=0, tmps=1) ; (before optimizer) ; hello.php:1-10 L0 (3): NOP L1 (8): INIT_FCALL 1 112 string("hello") L2 (8): SEND_VAL string("php") 1 L3 (8): DO_UCALL L4 (10): RETURN int(1) hello: ; (lines=5, args=1, vars=1, tmps=1) ; (before optimizer) ; hello.php:3-6 L0 (3): CV0($name) = RECV 1 L1 (4): NOP L2 (4): T1 = FAST_CONCAT string("HELLO ") CV0($name) L3 (4): ECHO T1 L4 (6): RETURN null call hello() declare hello() $ php -d opcache.opt_debug_level=0x10000 -d opcache.enable_cli hello.php

Editor's Notes

  1. mod_php も embeded も 非Winだと libphp7.so という名前であることが多いのが紛らわしい。 どちらも共有ライブラリで、前者は apache httpd 専用、後者は目的を限定しない
  2. PHP7で一貫した 64bit サポートを実現するにあたって、SAPI module の改修は必須だった。 しかし、SAPI だけでなく、サーバすらまともにメンテされていないものも多く、利用もされてないので労力を減らすために不要なSAPI の移植は断念したと ほとんどのサーバは FastCGI 話せるから、PHP-FPM (や cgi-fcgi)使えばWebサーバに依存せずに使えるよね ということらしい 8+15=23種
  3. * https://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html * https://fastcgi-archives.github.io/FastCGI_Specification.html
  4. 単一バイナリで複数の SAPI module php コマンドは通常 cli, -S オプション付きで起動すると cli-server 他の SAPI module を利用 nginx unit (nginx アプリケーションサーバ) は libphp (embed) を利用して、 独自の SAPI module (unit) を実装している
  5. php-cgi は、 CGIとしてもFCGI としても動作可能だけど、どちらも cgi-fcgi SAPI lsphp も似た感じ
  6. 一つの リクエストを処理している間、ほかのリクエストを処理することはできない リクエストをまたいでリソースが共有されない
  7. 起動後にプロセスを立ち上げておいて、リクエストが来たら空いているプロセスが順次処理する 一般的な PHP の実行モデル。 PHP がこうするのではなく、 Webサーバにこう動いてもらう という想定。 ただし、 fastcgi の場合は PHP 自身 (cgi-fcgi/fpm-fcgi) がこのような動きをする PHP Script のリソースがリクエスト単位であることが重要
  8. 一部のWebサーバは、リクエストをスレッドで処理する。 そんなケースにも対応したものが ZTS ZTS (Zend Thread Safety 版) が想定する実行モデル。 Webサーバではリクエストをプロセスではなくスレッドで処理する分、 (特にWin32 で) パフォーマンスが改善されることがある 反面、リクエスト前後でマルチスレッド対応の処理(共有されるメモリ領域を分離して利用するための処理)が入るため、PHPのパフォーマンスは落ちる。
  9. NOP は何もしないopcode。 コンパイラの最適化によって複数の opcode が統合された際にはよくこうなる。
  10. それまでデフォルトだった CALL に変わり、PHP7.2で CALL にGOTO を混合させた HYBRID がデフォルトに x86、x86_64、PPC64 以外の CPU アーキテクチャではCALL にフォールバックする https://www.mail-archive.com/internals@lists.php.net/msg91158.html https://github.com/php/php-src/commit/27e01cd918dd3309571aa3628e6139d436b10e18 (マージされたコミット) https://github.com/php/php-src/commit/fc927dc263f95b98a1a64124cce6028185ebbd00 (7.2 系で Hybrid がデフォルトになったコミット)
  11. PHP Script で C言語をジェネレート
  12. Turn safe timeout handling into general interrupt handling ability. https://github.com/php/php-src/commit/d0460d8f6be04fc9493fc7db99d29168b46f3e72
  13. 基本は chunk 単位での確保 もっとも最小の割り当ては chunk をさらに細分した page に含まれる slot 単位となる
  14. php script でメモリが必要になった時、 内部では emalloc という関数(マクロ) が呼ばれる メモリは segment 単位で確保されるが、その際、実際に OS に対してメモリを確保するのは選択可能な storage_handler segment
  15. ZEND_MM_COMPACT は https://bugs.php.net/bug.php?id=41713 への対応によるものらしい
  16. 関数定義 と 関数呼び出しが 別の op_array として生成される