PHPで失敗するかもしれない処理の返り値を配列で表現すると都合がいいという話

値を返すのに失敗するかもしれない処理を扱う場面というのは多い。
例えばあるファイルの中身を取得する処理について考えると、ファイルが存在する場合はその中身を取得して返すことができるが、そうでない場合は中身を取得するのに当然失敗する。
PHPに予め用意されているfile_get_contentsはまさにそれだが、この関数は処理に失敗するとfalseを返す。
ここでは別にもう一つ似た関数を作ってみる。

<?php

function my_file_get_contents($path)
{
    $buf = file_get_contents($path);
    return $buf === false ? array() : array($buf);
}

このmy_file_get_contents関数は、ファイルの中身を成功した場合は結果を持った配列を返し、そうでなければ空の配列を返す。
これからこのfile_get_contents関数とmy_file_get_contents関数の使いやすさを実際のコードと共に比較していく。

ファイルの中身を得ることができた場合にのみ処理する

file_get_contents関数の場合:

<?php

$result = file_get_contents('./foobar.txt');
if ($result !== false) {
    // 処理
}

my_file_get_contents関数の場合:

<?php

foreach (my_file_get_contents('./foobar.txt') as $result) {
    // 処理
}

成功した場合のみ結果を格納した配列を返すのでforeach文で成功した場合を扱うことができる。

複数のファイルの中身を取得できた場合にのみ処理する

file_get_contents:

<?php

$a = file_get_contents('./a.txt');
if ($a !== false) {
    $b = file_get_contents('./b.txt');
    if ($b !== false) {
        // 処理
    }
}

my_file_get_contents:

<?php

foreach (my_file_get_contents('./a.txt') as $a) {
    foreach (my_file_get_contents('./b.txt') as $b) {
        // 処理
    }
}

これも同様に成功した場合をforeach文で表現できる。

ファイルの中身を得られなかった場合に他の値を代わりに得る

file_get_contents:

<?php

$result = file_get_contents('./foobar.txt');
$result = $result !== false ? $result : 'failure';

my_file_get_contents:

<?php

list($result) = my_file_get_contents('./foobar.txt') + array('failure');

左辺のlist表現は、配列を要素を変数にセットするためのもので、配列同士の足し算は右の配列の要素を左の配列で上書きしていくものである。

あるファイルの中身を得られなかった場合に他のファイルの中身を取得する

file_get_contents:

<?php

$result = file_get_contents('./a.txt');
if ($result === false) {
    $result = file_get_contents('./b.txt');
    if ($result === false) {
        $result = 'failure';
    }
}

my_file_get_contents:

<?php

list($result) = my_file_get_contents('./a.txt') 
             ?: my_file_get_contents('./b.txt') 
             ?: array('failure');

PHPでは配列を真偽値として評価すると、要素をひとつ以上持っている配列はtrueとして、空の配列はfalseとしてみなされるので ?:演算子(PHP5.3以降)を使ってこのように記述できる。

ファイルの中身を得られた場合とそうでない場合の両方で処理をする

file_get_contents:

<?php

$result = file_get_contents('./foobar.txt');
if ($result !== false) {
    // 処理
}
else {
    // 処理
}

my_file_get_contents:

<?php

$result = my_file_get_contents('./foobar.txt');
if ($result) {
    // 処理
}
else {
    // 処理
}

結論

失敗するかもしれない処理の返り値を配列で表現すると、以上のように違った書き方ができる。場合によっては返り値を配列で扱う方が都合がいい。