PerlとPHPにおける「リスト」概念の違い

naoyaさんのPHP版 List_RubyLikeを見ていて面白いことに気づきました。

$list->push('foo');
$list->push('bar','buz');

一瞬、「なんて美しい!」と思いました。
と同時に、「なんてPerl的な!」とも思いました。
「これじゃまるでPerlじゃないか」と。

私ならこういうインターフェイスにすると思います。

$list->push('foo');
$list->push(array('foo','bar'));

少し冗長ですが、こっちの方がPHPとしてしっくりきます(私にとっては)。
実際にはpush(array('foo','bar'))などとリテラルを渡すことはあまりなくて、push($hoge)とかpush($this->hoge())などと書くことになるでしょう。

この違いを突き詰めていくと、「PerlとPHPにおけるリストの考え方が違うんだ」という面白い事実を発見しました。

PHPプログラマとPerlプログラマのものの見方の違い


func('foo', 'bar');

このコードを見たとき、
PHPプログラマは「関数に2つの値を渡している」と考えます。
一方、
Perlプログラマも「関数に2つの値を渡している」と考えますが、
同時に「関数に1つのリストを渡している」とも考えます。

Perlにおいて、下記の2つのfunc呼び出しは同じ意味です。

func(1,2,3);

my @list = (1,2,3);
func(@list);

ところがPHPにおいては、下記の2つのfunc呼び出しは意味が異なります。

func(1,2,3);

$list = array(1,2,3);
func($list);

サンプルコード

Perl
use strict;
use Data::Dumper;

func(1,2,3);

my @list = (1,2,3);
func(@list);

sub func() {
    print Dumper \@_;
}

---結果---

$VAR1 = [
          1,
          2,
          3
        ];
$VAR1 = [
          1,
          2,
          3
        ];
PHP
<?php

func(1,2,3);

$list = array(1,2,3);
func($list);

function func() {
    $args = func_get_args();
    print_r($args);
}

---結果---
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
)
Array
(
    [0] => Array
        (
            [0] => 1
            [1] => 2
            [2] => 3
        )

)

もちろん、func_get_argsの戻り値に応じてif文で分岐すればPerlと同じ振る舞いをさせることはできます。
しかしそこまでやってしまうとPHPらしくない気がします。
何故かというと、PHPの配列関数(array_*系の組込み関数)はPerlのような「引数のリスト渡し」をサポートしていないからです。

参考:Perlにおける配列とリストの違い

リストとは、スカラーの集合に順序を付けて並べたものです。
配列とは、リストを保持する変数のことです。
リストはデータであり、配列は変数であるという違いがあります。
--- 「初めてのPerl」3章 リストと配列
PHPでも「array型のデータ」と「arra型の変数」は異なる概念です。
しかし「スカラーを並べたものをリストと呼ぶ」という考え方はない気がします。

結論

  • PHPに「リスト」というものはない。ただarray型のデータとarray型の変数があるのみ。
  • func_get_argsは@_の代わりにはならない。
※誤解のないように言っておくと、naoyaさんのList_RubyLikeを批判しているわけではありません。
「PHPらしい、らしくない」はあくまで私の主観です。

ご意見、ツッコミあればお願いします。
カテゴリ: