SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

PHPエクステンションの作り方

PHPでのストリーム処理の実装

PHPエクステンションの作り方 第6回

ストリームの読み込みとクローズ処理をするための関数の作成

 今回は、読み込みのみのために必要な関数はreadとcloseの2つの関数のみです。これ以外にも、以下の関数をストリームを扱う関数として登録できます。

ストリームを扱う際に実装できる関数の一覧
命令 説明 対応するPHPの関数
write ファイルの書き込み処理 fwrite()
read ファイルの読み込み処理 fread()
close ファイルを閉じる処理 fclose()
flush ファイル書込時のflush処理 fflush()
seek ストリーム内の場所の移動 fseek()
stat ストリームリソースについての情報の取得 fstat()
cast 元のリソースを取得 stream_select()
set_option ストリームのオプション設定 対応なし

 では、読み込み処理から実装します。

ストリームからの読み込み(pzip_stream.cの抜粋)
static size_t php_pzip_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
{
    struct php_pzip_stream_data_t *self = (struct php_pzip_stream_data_t *)stream->abstract;  // ……(1)
    ssize_t n = 0;
    
    if(self->zf){
        n = zip_fread(self->zf, buf, count);  // ……(2)
        if ( n < 0){
            return 0;
        }
        if ( n == 0 || n < (ssize_t)count){   // ……(3)
            stream->eof = 1;                  // ……(4)
        }
        else{
            self->cursor += n;                // ……(5)
        }
    }
    return (n < 1 ? 0 : (size_t)n);           // ……(6)
}

 (1)のようにして、引数のstreamから先ほど作成したストリームの状態を管理している構造体にアクセスができます。次に、(2)のように実際にリソースからデータを読み込む処理を記述します。どの程度のデータを読むかは引数のcountになり、同様に読み込んだデータは引数のbuf変数に設定します。また、実際に読み込んだデータが0バイト、もしくは(2)で指示したサイズよりも小さいということは最後のデータまで読み込まれたということなので、(4)のようにstream->eofに1を立ててストリームの終端まで読み込んだフラグを立てます。また、(5)では、実際に読み込んだデータの総量をカウントし、(6)で今回に実際に読み込んだデータサイズを返します。

 続いて、クローズ処理を実装します。

ストリームのクローズ(pzip_streamcの抜粋)
static int php_pzip_ops_close(php_stream *stream, int close_handle TSRMLS_DC)
{
    struct php_pzip_stream_data_t *self = 
       (struct php_pzip_stream_data_t *)stream->abstract;  //……(1)
    if(self->zf){
        zip_fclose(self->zf);  // ……(2)
        self->zf = NULL;
    }
    efree(self);                  // ……(3)
    stream->abstract = NULL;
    return EOF;                   // ……(4)
}

 (1)は先ほどとまったく同様で、ストリームの状態を管理している構造体にアクセスします。このコードは各命令で同じになるので、実際にはマクロなどを作成して、それを利用するケースが多々あります。後は、(2)のようにそのリソースに沿ったclose処理を行い、(3)のように状態管理の構造体自身のメモリも解放します。(4)のように最後にEOFを返せば、クローズ処理の実装も終了です。

ハンドラ関数登録の構造体の作成

 今まで作成してきた関数をPHP側で認識できるように構造体に設定する必要があります。

ストリームのハンドラ関数の構造体(pzip_stream.cの抜粋)
php_stream_ops php_stream_pzip_ops = {  // ……(1)
    NULL,  // write
    php_pzip_ops_read,                  // ……(2)
    php_pzip_ops_close,                 // ……(3)
    NULL,  // flush
    "pzip",  // label
      : (省略)
};

 そのためには、(1)php_stream_opsの構造体を作成し、(2)(3)のように先ほど作成した関数を登録します。この構造体は、php_stream.hで定義されており、ストリームに関する定義はそのヘッダファイルを見ることで、詳しい定義が分かります。

ストリームのオープン処理

 最後に、ストリームのオープン処理です。オープン処理だけは構造体で管理されずに、プログラマ自身が作成する必要があります。

ストリームのオープン処理(pzip_stream.cの抜粋)
php_stream *php_stream_pzip_open(struct zip_file *zf, char *mode STREAMS_DC TSRMLS_DC)  // ……(1)
{
    php_stream *stream = NULL;
    struct php_pzip_stream_data_t *self;  // ……(2)
    
    if(zf){
        self = emalloc(sizeof(*self));    // ……(3)
        self->zf = zf;
        self->cursor = 0;
        stream = php_stream_alloc(&php_stream_pzip_ops, self , NULL ,mode);  // ……(4)
        
        if(stream){
            return stream;
        }
        else{
            return NULL;
        }
    }
    else{
       return NULL;
    }
}

 (1)php_streamの戻り値を返す関数を定義します。この関数はPZipFile::getStream()の中で利用するためのものです。実際には、その関数内でopenされたストリームを引数を引数に呼び出されます。(2)で、ストリームの状態を管理する構造体の変数を用意し、(3)で実際にメモリを確保します。(4)でPHPのストリームを作成します。その際に、ストリームの操作を設定した構造体変数と、(2)で用意した変数を設定します。

 以上で、メソッドを通じてストリームを取得方法が完了しました。

次のページ
URL記述からのPHPストリームの作成

この記事は参考になりましたか?

PHPエクステンションの作り方連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)

WINGSプロジェクト について> 有限会社 WINGSプロジェクト が運営する、テクニカル執筆コミュニティ(代表 ...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/7576 2014/01/21 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー