CodeZine(コードジン)

特集ページ一覧

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

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

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2014/01/21 14:00
目次

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

 今回は、読み込みのみのために必要な関数は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)で用意した変数を設定します。

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


  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

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

著者プロフィール

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

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。個人紹介主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしど...

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

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5