書籍概要

PHPはどのように動くのか
PHPコアから読み解く仕組みと定石

著者
発売日
更新日

概要

同じようなスクリプトなのに,なぜパフォーマンスが違うのか?
オブジェクト指向だと,なぜ遅いのか?
PHP7は,なぜ速くなったか?

最も人気のあるWeb用プログラム言語であるPHPの知られざる内部構造を解説した,日本初の書。「メモリを節約したり,処理を軽くしたりするスクリプトを書くには」「パフォーマンスの高いExtensionを作るには」「Zend Engineをハックするには」といった,ほかにはない話題が満載です。

こんな方におすすめ

  • PHPの仕組みを知り,定石やパフォーマンスの背景について理解を深めたい中上級者

著者から一言

PHPは最も人気のあるWebサイト用プログラム言語です。ほとんどのレンタルサーバで使うことができたり,大手のWebサイトで使用されていたりします。また,PHP開発者の数も多く,出版されている書籍やWebサイトもたくさんあります。PHPが現在のような地位を築けたのは,文法が比較的かんたんでなじみやすく,機能や標準関数が充実しているからでしょう。

このように幅広く普及し,数多くのWebサイトを作り上げているPHPは,はたしてどのように動いているのでしょうか?

本書は,おそらく日本では初めてとなる,PHPの内部構造,つまりPHPコアをテーマとした本です。これまでに,PHPの言語ルールやコーディング方法,TIPSについて解説した本はたくさんありましたが,PHPの奥深くに触れた本はありませんでした。あったとしても,せいぜいExtensionを開発する手法をかんたんに紹介するだけにとどまっていたと思います。

では,PHPコアを理解すると,どのような良いことがあるのでしょうか?

まず,メモリを節約したり,処理を軽くしたりするスクリプトを書けるようになります。パフォーマンスの高いExtensionを開発するのにも役立つことでしょう。そして何よりも,これまでブラックボックスだったPHPの内部を知ることによって,自分の能力に自信を持てるようになり,プログラミングがより楽しくなり,学習欲もさらに高まるはずです。

内容はPHPの内部のことであり,C言語で書かれているので,必ずしもかんたんというわけではありません。しかし,OSや言語を自分自身でゼロから創造するような難しさがあるわけでもありません。PHPの内部で起きている事象について流れを追っていくので,読み物として気楽に読んでください。また,これまでに莫大なスクリプトを書いてきた方も,これから“Hello, world!”を書くという方も,「PHPの内部構造をよく知らない」という意味ではまったく同じです。PHPという言語に興味を持ち,中を覗きたくなった方には,その好奇心を満たす内容となっています。

さぁ,未知の世界であったPHPコアを覗く旅に出かけましょう!

目次

第1章 なぜ,同じようなスクリプトなのにパフォーマンスが違うのか

スクリプトの良し悪しは何で決まるのか

  • 処理速度はスクリプトの前後の文脈に依存する
  • 内部構造を知ることが正確な判断への手がかり
  • 処理速度を計測するには
  • 論理の判断

スクリプトを比較する

  • forの最大値が変数 vs. 関数
  • 条件分岐 if else vs. 三項演算子
  • 比較演算子 == vs. ===
  • エラー制御演算子がない vs. ある
  • 連想配列の添え字がクォートなし vs. シングルクォート
  • PHPのバージョン取得 phpversion() vs. PHP_VERSION
  • 標準出力 print() vs. echo()
  • echoに渡す引数 カンマ vs. ドット

第2章 オペコードのパフォーマンスを考える

プログラムが実行される仕組みをおさえる

  • オペコードはどのように生成され,実行されるか
  • 字句解析と構文解析で行われること
  • オペコードが実行されるまでの流れをつかむ
  • コンパイル処理の流れをおさえる
  • どのようにしてオペコードが演算されていくのか

パフォーマンスに影響するオペコードをおさえる

  • 型によるパフォーマンスの違い
  • 代入によるパフォーマンスの違い
  • 関数や引数の処理によるパフォーマンスの違い
  • 特殊な処理によるパフォーマンスの違い

第3章 PHPコアの仕組みと開発の定石を知る

メモリの仕組みと定石

  • メモリの確保
  • メモリの解放
  • メモリを操作するAPI

zvalの仕組みと定石

  • zvalに関連した構造体
  • コピーオンライトの仕組みをおさえる
  • zvalを生成/解放する
  • zvalの変数を配列にする
  • zvalの種類を取得する
  • zvalの型を調べる
  • zvalの値を取得する
  • zvalの値を設定する
  • zvalの型を変換する

HashTableの仕組みと定石

  • HashTableにキーとデータを登録する流れ
  • HashTableにキーと値を登録する
  • HashTableのキーに対する値を更新する
  • HashTableへ値を登録する
  • HashTableのインデックスに対する値を更新する
  • HashTableのキーと値を削除する
  • HashTableのインデックスと値を削除する
  • HashTableを展開する
  • HashTableを検索する

クラスの仕組みと定石

  • 構造体zend_object_valueの中を覗く
  • オブジェクトを生成する

関数の仕組みと定石

  • 引数を処理する
  • 引数を参照渡しする
  • 戻り値を設定する

出力の仕組みと定石

  • 標準出力の中身を覗く
  • エラー出力の中身を覗く

第4章 オブジェクト指向だとなぜ遅いのか

クラスの仕組みを覗く

  • クラスの宣言ではどのようなことが行われているか
  • クラスの継承ではどのようなことが行われているか

オブジェクトの仕組みを覗く

  • プロパティを読み込む場合はどのようなことが行われているか
  • プロパティに書き込む場合はどのようなことが行われているか
  • メソッドを実行する場合はどのようなことが行われているか

第5章 PHP7はなぜ速くなったか

HHVMとPHP7

  • HHVMが超高速に動作する理由
  • PHP7はインタプリタ言語でありながらパフォーマンスが高められた

zvalで何が変わったか

  • PHP5のzvalとPHP7のzvalを比較すると
  • 文字列へのアクセスが速くなった
  • 配列型ではHashTableへのアクセスが悪くなった
  • オブジェクトでプロパティを探索するのが速くなった
  • コピーオンライトでポインタをたどるオーバーヘッドがなくなった
  • 変数の扱い方がどのように変わったのか

HashTableで何が変わったか

  • HashTableとBucketの構造体を比較すると
  • Bucketを動的に確保せず,走査も高速に

関数における引数の処理で何が変わったか

  • PHP5では関数の解析でパフォーマンスが落ちていた
  • マクロを利用することでパフォーマンスを高められるように

第6章 Extensionを作る

開発の前におさえておきたいこと

  • PHPコアのライブラリを把握する
  • ビルド環境を構築する

関数をExtensionとして書き直す

  • 元になる関数のスクリプト
  • モジュール構造体の中身や基本的なマクロを知る
  • モジュール構造体に関数を登録する
  • Extensionにおける関数を定義する

関数をクラスとして作りなおす

  • 元となるクラスのスクリプト
  • クラスにメソッドを紐づける
  • クラスを登録してプロパティを追加する
  • メソッドを定義する

C++のクラスをExtensionのクラスに

  • 元となるC++のクラス
  • テンプレートライブラリを用意する
  • Extensionのクラスを実装する
  • Extensionのクラスを登録する

第7章 Zend Engineをハックする

オペコードの8つの分類を把握する

exitでも終了しないようにする

スクリプトで関数を作れないようにする

クラスのインスタンスを生成できないようにする

includeをinclude_onceに,requireをrequire_onceに強制的に変更する

新しい構文を追加する

Appendix オペコード一覧

サポート

正誤表

本書の以下の部分に誤りがありました。ここに訂正するとともに,ご迷惑をおかけしたことを深くお詫び申し上げます。

(2015年11月11日更新)

P.5 最終行

コンマ
ドット

P.13 図「PHPコアのアーキテクチャ」

構文解析(baison)
構文解析(bison)

P.22 1行目

==
===

P.28~P.29

コンマ
ドット

P.42

冒頭2行のオペコード例は,前のページからの続きなので,囲みの色はグレーではなく黒になります。

P.57 1行目

メモリ管理は、プログラムにおいて、最も需要な機構といえるでしょう。
メモリ管理は、プログラムにおいて、最も重要な機構といえるでしょう。

P.71 ポインタのポインタ

long val = Z_LVAL_P(z);
long val = Z_LVAL_PP(z);

P.83 リスト「HashTableへ値を登録する」

zend_hash_next_index_update
zend_hash_next_index_insert

P.83 リスト「HashTableのインデックスに対する値を更新」

zend_hash_next_index_update
zend_hash_index_update

P.139 12~13行目

構造体value
共用体value

P.153 図「PHP7でのHashTableの構造」

pListHead
arData

pListTail
arHash

Bucket *
Bucket Index

2箇所あります。

商品一覧