クラスのインスタンスを返す方法と引数として利用する方法
続いて、クラスのインスタンスを返す方法や、引数として利用する方法を紹介します。クラスのインスタンスを返すことで、配列と同様に一度に多くのデータを戻すことができ、また配列とは違い、よりデータへのアクセス方法が管理されたデータをPHP側に戻すことができます。そして、引数にクラスのインスタンスを使えば、プリミティブな値と違ってPHPエンジニア側のタイプミスなどが起こりにくくなります。クラス構成でエクステンションを作成する場合には、ぜひ利用したいテクニックの一つです。
メソッドの中でクラスのインスタンスを返す
PZipEntryクラスのインスタンスを返すメソッドを実装します。実際に実行される時のPHPのコードは、以下のようになります。
$entry = $pzip_file->getEntry(0);
また、クラスのインスタンスを返すエクステンション側の実装は以下のようになります。
PHP_METHOD(PZipFile, getEntry){ : // (省略) php_pzip_entry *entry; : // (省略) else{ : // (省略) object_init_ex(return_value, pzip_entry_ce); // ……(1) Z_SET_REFCOUNT_P(return_value, 1); // ……(2) Z_SET_ISREF_P(return_value); // ……(3) entry = (php_pzip_entry *)zend_object_store_get_object(return_value TSRMLS_CC); //……(4) entry->stat = stat; // ……(5) } }
(1)でPZipEntryのzend_class_entryである、pzip_entry_ceを指定し、インスタンスを初期化します。(2)、(3)はインスタンスの参照カウンタを設定します。参照カウンタについては、http://www.php.net/manual/ja/features.gc.refcounting-basics.phpを参照すると詳しいことが分かります。(4)zend_object_store_get_objectでreturn_valueの変数から、クラスの内部データを管理するphp_pzip_entryの構造体を取得します。(5)では、その構造体に値を設定していきます。同様にほかの変数に値を設定することも可能です。
クラスのインスタンスを引数として利用する
クラスのインスタンスを引数から取得するには、ほかと同様にzend_parse_parameters()を利用すればよいので、非常に簡単に取得できます。
PHP_METHOD(PZipFile, getStream){ : // (省略) zval *z_entry; php_pzip_entry *entry; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_entry, pzip_entry_ce) == FAILURE ){ // ……(1) return; } entry = (php_pzip_entry *)zend_object_store_get_object(z_entry TSRMLS_CC); // ……(2) : // (省略) if(entry->stat->encryption_method){ // ……(3) if(!obj->password){ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Please set password"); RETURN_FALSE; } zf = zip_fopen_index_encrypted(obj->zip,entry->stat->index,flags,obj->password); // ……(4) } else{ zf = zip_fopen_index(obj->zip,entry->stat->index,flags); // ……(5) } : // (省略) }
(1)zend_parse_parameters()の第1引数に"O"を指定し、第2引数には実際に値が設定されるzvalの変数、第3引数にはクラスの型を示すzend_class_entryの型であるpzip_entry_ce変数を設定します。そして、そのクラスの内部データ構造体の変数を取得するには、(2)zend_object_store_get_object()を利用します。このとき、引数として(1)で取得したzvalの値を引数に設定します。これで構造体にアクセスできたので、後はそれぞれの実装をしていくことが可能です。
今回のサンプルでは、(3)のようにZIPのエントリーから暗号方式の情報を取得し、その状況に合わせて、(4)暗号解読方式でのZIPエントリデータのオープン、もしくは、(5)通常法方式でのZIPエントリデータのオープンをしています。
以上でクラスのひな形としての実装は終了しました。ただし、実際にzip_fopen_index関数を通じて取得したリソースは、まだ扱うことができません。次回はそのリソースをPHPでのストリーム関数を通じてアクセスできるようにします。
最後に
今回はlibzipというライブラリを組み込み、PHPで標準的に用意されているZipArchiveで足りない部分を補うことができるようにサンプルコードを紹介しました。実際のエクステンションの開発をゼロから行うことはなくても、既存のエクステンションに機能を追加することができれば、より利用シーンが広がると思います。
また、PHPのメリットの一つに、ネイティブライブラリのブリッジモジュールを簡単に作れることがあります。今までコマンドラインなどを通じて、ネイティブライブラリを利用しているケースでは、そのライブラリをPHP自体に組み込むことで、コマンドラインなどで扱うよりも柔軟にそして軽量に構築が行えます。そして、PHPでできない、もしくは苦手としている領域のプログラムをカバーすることができ、技術を使い分けることでより高度なプログラムスキルがつくことと思います。