2011-01-31 00:50:20
来月開催される ZendEngine勉強会@東京に向けて, 少しでも予習しておこうと思い, 以下のページを参考にやってみました.
PHP Extension を作ろう第1回 - まずは Hello World DSAS開発者の部屋
しかし, この記事そのままのやり方では上手くいきませんでした.
書かれたのが 2006 年ということもあり, 一部情報が古くなっている部分があるようです.
そこで, 上記の記事を参考にしつつ, 調べてまとめてみました.
0. 前提とする環境
私は以下の環境で検証を行いました.
LAMP 環境は tasksel コマンドで構築したものです.
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=10.10
DISTRIB_CODENAME=maverick
DISTRIB_DESCRIPTION="Ubuntu 10.10"
$ php -v
PHP 5.3.3-1ubuntu9.3 with Suhosin-Patch (cli) (built: Jan 12 2011 16:08:14)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
$ apache2ctl -v
Server version: Apache/2.2.16 (Ubuntu)
Server built: Nov 18 2010 21:17:29
$ gcc -v
Using built-in specs.
Target: i686-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.4.4-14ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
Thread model: posix
gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)
また, phpize というコマンドが必要になるのでインストールしておきましょう.
Debian/Ubuntu であれば以下のコマンドでインストールできると思います.
$ sudo apt-get install php5-dev
1. PHP のソースコードを入手する
Zend API を利用するためのヘッダファイルや, PHP Extension を作るためのスケルトンを生成するプログラム等を手に入れるのが目的です.
2011/01/31 現在の最新版は 5.3.5 ですが, ローカルにインストールされているバージョンに合わせて, 私は 5.3.3 をダウンロードしています.
適当なディレクトリにダウンロードして, 展開します.
$ sudo tar xvzf php-5.3.3.tar.gz -C /path/to/somewhere
2. PHP Extension のスケルトンを生成する
コマンド一発で, スケルトン (ひな形) のファイル群を生成してくれます.
これで生成されたファイルをもとに, PHP Extension を作っていきます.
$ cd /path/to/someshere/php-5.3.3/ext
$ ./ext_skel --extname=helloworld
Creating directory helloworld
Creating basic files: config.m4 config.w32 .cvsignore helloworld.c php_helloworld.h CREDITS EXPERIMENTAL tests/001.phpt helloworld.php [done].
To use your new extension, you will have to execute the following steps:
1. $ cd ..
2. $ vi ext/helloworld/config.m4
3. $ ./buildconf
4. $ ./configure --[with|enable]-helloworld
5. $ make
6. $ ./php -f ext/helloworld/helloworld.php
7. $ vi ext/helloworld/helloworld.c
8. $ make
Repeat steps 3-6 until you are satisfied with ext/helloworld/config.m4 and
step 6 confirms that your module is compiled into PHP. Then, start writing
code and repeat the last two steps as often as necessary.
3. config.m4 を編集する
以下の箇所のコメントアウトを外します.
この辺は元の記事に従っています.
4. helloworld() 関数を追加する
php_helloworld.h を以下のように編集します.
そして, helloworld.c も編集します.
5. ビルドする
以下のコマンドを, helloworld.c 等のファイルのあるディレクトリ上で実行します.
$ phpize
$ ./configure
$ make
これでビルドは完了です.
ここで, 今ビルドした Extension を読み込んで試してみたいところですが, ここからが問題です.
元の記事のとおりではうまく読み込むことができないので, さらにいくつかの設定が必要です.
6. dl() 関数を有効にする
dl() 関数とは, PHP Extension を Dynamic Load (動的読込) を行う関数ですが, デフォルトでは使えないように設定されているようです.
無効化されている場合は, dl() の呼び出し時に以下のようなエラーメッセージが表示されます.
$ php -a
Interactive shell
php > dl("helloworld.so");
PHP Warning: dl(): Dynamically loaded extensions aren't enabled in php shell code on line 1
php.ini で dl() 関数を有効化しましょう.
CLI 版 PHP の php.ini のパスは以下のようにして調べられます.
Debian/Ubuntu の場合は, デフォルトでは Apache2 用と CLI 用とで php.ini が分かれているので注意しましょう.
$ php -i | grep "Configuration File"
Configuration File (php.ini) Path => /etc/php5/cli
Loaded Configuration File => /etc/php5/cli/php.ini
Apache2 の mod_php の設定ファイルのパスは, PHP スクリプト内で phpinfo() 関数を呼び出し, Web ブラウザ上で確認できます.
php.ini のパスを確認したら, 以下のように編集しましょう.
enable_dl = On
7. helloworld.so を extension_dir に置く
元の記事では, dl() 関数に相対パスを渡して helloworld.so を読み込んでいますが, セキュリティ上の理由からか, ファイル名しか指定できなくなっているようです.
ディレクトリ名を指定した場合, 以下のようなエラーメッセージが表示されます.
$ php -a
Interactive shell
php > dl('module/helloworld.so');
PHP Warning: dl(): Temporary module name should contain only filename in php shell code on line 1
php.ini で設定した extension_dir に helloworld.so を置く必要があります.
extension_dir は以下のように調べられます.
$ php -i | grep extension_dir
extension_dir => /usr/lib/php5/20090626+lfs => /usr/lib/php5/20090626+lfs
mod_php の場合は, やはり phpinfo() をブラウザ上から確かめる必要があります.
ビルドする度にコピーするのでは面倒なので, ここではシンボリックリンクを使用しています.
$ sudo ln -s /path/to/php-5.3.3/ext/helloworld/modules/helloworld.so /usr/lib/php5/20090626+lfs/
8. 実行する
$ php -a
Interactive shell
php > dl('helloworld.so');
php > helloworld();
Hello, World!
見事, helloworld() 関数を実行することができました !
今回はここまでです.
これを元に, 私も何か PHP Extension を作っていきたいと思います.
See also
2010-12-31 05:08:00
PHP の interface や implements ってご存知ですか ? 知っている前提で話を進めます。
それでは PHP の組込みインターフェイスをご存知ですか ?
この記事ではそれについて紹介します。
なお、PHP のバージョンは 5.3 以降を前提としています。 (多分、 5.2 でも動く)
PHP の組込みインターフェイスとは
PHP でインターフェイスを定義するには、 interface 宣言を記述する必要があります。
しかし、以下のようなインターフェイスは PHP に予め組込まれており、定義すること無しに利用できます。
普通 interface といえば、メソッドの定義を強制することで、クラスの再利用性を高めるために用いられていると思います。
上記の組込みのインターフェイスについても、もちろんそういった利点があります。
ですが、組込みインターフェイスには、通常のクラス定義ではあり得ない振る舞いをオブジェクトに持たせることができるものがあります。
要は 普通じゃないオブジェクトを作れる ということです。
配列っぽいオブジェクトをつくる
ここからは、PHP の組込みインターフェイスの便利さを知ってもらうために、配列っぽいオブジェクトの作り方を説明します。
さて、配列っぽいってどういうことでしょうか ?
配列、つまり PHP の array 型は、以下のような使い方ができますね。
以下では、array 型が持つこれらの機能を、オブジェクトに実装していきます。
(0) コンストラクタ
まずは、 array をプロパティとして持つ ArrayLike クラスを定義します。
<?php
class ArrayLike
{
protected $_arr;
public function __construct($arr = array())
{
$this->_arr = $arr;
}
}
ArrayLike オブジェクトは以下のように生成します。
<?php
require_once 'ArrayLike.php';
$arrObj = new ArrayLike(array('foo', 'bar', 'baz'));
以下では省略しますが、 $arrObj はすべてこのように生成しているという前提でお読みください。
(1) 要素数を数える (Countable)
現状ではこうなります。
<?php
echo count($arrObj), PHP_EOL; // => 1
3 となって欲しいところですが、なりません。
オブジェクトに count() 関数を適用すると、通常は常に 1 となるようです。
(count 関数のマニュアルには「オブジェクトに含まれるプロパティの数を数える」となってますが間違いのようです)
そこで、 ArrayLike クラスに次のような変更を加えましょう。
最初に宣言したプロパティや定義したメソッドは省略します。
<?php
class ArrayLike implements Countable
{
public function count()
{
return count($this->_arr);
}
}
Countable というインターフェイスに定義されている count() メソッドを実装しました。
すると、 count() に対する ArrayLike オブジェクトの振る舞いはいかのようになります。
<?php
echo count($arrObj), PHP_EOL; // => 3
期待通りの値が返ってきました !
これで配列に一歩近づきましたね。
(2) 要素を 1 つ 1 つ列挙する (Iterator)
foreach 構文にオブジェクトを渡すと、通常は public なプロパティが列挙されます。
ArrayLike オブジェクトは public なプロパティを持たないので、 foreach は空振りします。
構文エラーではありませんが、やはり配列として期待する動作とは違います。
そこで、再び ArrayLike クラスに変更を加えます。
先ほどまでに実装している部分は省略しています。
実装するメソッド数がさっきより多いので、詳細は気にせず「Iterator インターフェイスのメソッドを実装した」ことだけ理解していただけで問題ありません。
<?php
class ArrayLike implements Countable, Iterator
{
protected $_index;
public function rewind()
{
$this->_index = 0;
}
public function key()
{
return $this->_index;
}
public function current()
{
return $this->_arr[$this->key()];
}
public function next()
{
$this->_index++;
}
public function valid()
{
return $this->_index < $this->count();
}
}
すると、 foreach に対する ArrayLike オブジェクトの振る舞いは以下のようになります。
<?php
foreach ($arrObj as $key => $value) {
echo "{$key}:{$value}", PHP_EOL;
}
// =>
// 0:foo
// 1:bar
// 2:baz
だいぶ配列に近づいてきましたね。
(3) 要素へ値の代入と取得 (ArrayAccess)
count や foreach のときと違い、オブジェクトに対して [] 演算子を使うと Fatal error となります。
<?php
$arrObj[1] = 'foo'; => PHP Fatal error: Cannot use object of type ArrayLike as array in...
というわけで、さらに ArrayLike に手を加えます。
例によって、今までに実装したメソッドや宣言したプロパティは省略しています。
<php
class ArrayLike implements Countable, Iterator, ArrayAccess
{
public function offsetSet($key, $value)
{
$this->_arr[$key] = $value;
}
public function offsetGet($key)
{
return $this->_arr[$key];
}
public function offsetExists($key)
{
return isset($this->_arr[$key]);
}
public function offsetUnset($key)
{
unset($this->_arr[$key]);
}
}
さて、再び [] 演算子を使ってみましょう。
<?php
$arrObj[1] = 'foo';
echo $arrObj[1], PHP_EOL; // => foo
これはもうほとんど配列ですね。
完成
ここまでで実装してきたものをまとめると以下のようになります。
まとめ
PHP の組込みインターフェイスを使うと、普通のクラス定義ではありえない振る舞いをオブジェクトに持たせることができます。
また、言語組込みのインターフェイスなので、とりあえずこれに従っておけば、メソッドの命名で喧嘩せずに済むかもしれません。
See also
2010-12-23 23:14:19
[caption id="attachment_981" align="alignright" width="240" caption="パーフェクト PHP"]
[/caption]いきなり結論
少なくとも PHP 5.3 時代である現在、この本の登場をもって、これまでにあった有象無象の「PHP と MySQL でインタラクティブなホームページをつくろう !」的な本はその役割を終えました ... と言えるぐらい網羅されているので、買いましょう。
この書籍のターゲット
購入前のイメージでは中級者以上向けかと思っていましたが、手に取って読んでみると、初心者も対象に含まれているようで、 PHP のインストールや、文法の概要についてもカバーされていました。
ある程度 PHP を使いこなしている人であれば、読み飛ばす箇所も結構あると思いますが、言語仕様の細かい部分で「これは知らなかった」という部分にも出会えます。
例えば、リファレンスカウントによるガベージコレクションの仕組みや、コピーオンライトによる最適化については、知らない人も結構いると思います。 (少なくとも、私は PHP でコピーオンライトが使われていると意識したことはありませんでした)
個人的には、 みたいに、「これを読めば PHP ハッカーになれる !」みたいなのを期待していましたが、そういうのは想定されいないようです。
その分敷居はやや低めなので、 PHP 入門以前の方も安心して楽しめます。
書いてあること
- インストール方法
Linux, Mac のパッケージマネージャによるインストールと、 Windows では XAMPP によるインストール方法が紹介されています。
- 内部処理の概要
レキサー、パーサー、オペコードについての簡単な説明。
- 基本的な文法
既に PHP が書ける人であれば読み飛ばせる。
- PHP 5.3 以降の新しい機能
名前空間、無名関数、クロージャ、クラスのオートローディングなどについてもしっかり詳解されています。
業務ではまだ 5.2 以前の PHP を使っている、という人も覚えておきたい内容。
- Web アプリケーションの作成
フレームワークを作成して、それを基に Twitter ライクな Web アプリケーションを作成しています。
フレームワーク自体は割とミニマムにまとまっているので、いわゆるフレームワークが何をしてくれるのか、というのを雑観するのにもいいと思います。
- セキュリティ
XSS, CSRF, SQL インジェクションをはじめとして、具体的な攻撃手法とその対策が紹介されています。
全 PHP エンジニアが理解しておくべき内容。
- やや高度な機能
主に PHP5 以降のオブジェクト指向的な何かについて。
マジックメソッド、標準インターフェイス、SPL、PDO、DateTime、JSON 等。
- 雑多なテクニック
いわゆるレシピ。
書いてないこと
- 既存オープンソースフレームワーク解説
symfony のシの字も、 Ethna のエの字もありません。
著者の中にはそれらの関係者の方もいますが、意図的にトピックから外しているようです。
- テスト駆動開発
みたいに、そこまで触れるというのもありだとは思いました。
とはいえ、具体的なフレームワークの紹介は行わない方針のようなので、そういった意味でもしょうが無いですねこれは。
- PEAR/PECL パッケージの作り方
それぞれの概要については触れられるものの、パッケージの作り方については特に言及されていません。
Openpear についての宣伝があっても誰も怒らないとは思うのですが ...
- オブジェクト指向それ自体の説明
「PHP におけるオブジェクト指向」には触れられていますが、それ以上については専門書を読みましょう。
- コーディング規約
個人的にはモダン PHP を語る上では、結構重要なトピックだと思っています。
結構斜め読みで読み終えているので、「これについてはちゃんと書かれていたよ !」というのがあればご指摘いただければ幸いです。
初心者にオススメしたい活用法
PHP 初心者、もしくはこれから入門、という方に「こういう勉強法はどうでしょう ?」ということでオススメします。
といっても私自信がこれを実践したわけではないので、あまり偉そうには言えませんが ...
あくまでも「いち提案」として。
- Part 1 を読みながら、ローカルに開発環境を構築する
- Part 3 の実践 Web アプリケーション開発をひたすら写経
Part 2 の言語仕様をいきなり読むのは大変なので、じっくり読むのは何となくで PHP が書けるようになってから
- Part 4 の PHP セキュリティについての読書会を行う
業務で PHP を使っているのであれば、是非チームで共有しましょう
- Part 5 のテクニカルな PHP の活用、 Part 6 の PHP レシピはすき間時間等に読んでおき、「こんなこともできるのかー」程度に頭にいれておく
Part 4 の読書会は、私も自社内でやってみたいところです。
その他に読んでおきたい PHP 本
パーフェクト PHP が登場してもなお、その存在価値を失わないと思われる PHP 本を紹介します。
個別のフレームワークの解説本等は外し、より多くの PHP エンジニアに読まれるべきものを選んでいます。
未だにお世話になっていますが、残念ながら絶版となってしまいました ...
その代わり、現在は Web 上で読むことができます。
>> 書籍「PHPによるデザインパターン入門」の原稿テキストを公開します
安くて、薄くて、すっきり読めて、ためになるのでオススメです。
パーフェクト PHP のセキュリティ関係のパートだけでも同じぐらいの量はありますが、こちらにしか書いていない内容もあります。
PHP のサンプル自体はややレガシーな感もありますが ...