PHPのlist()はタプル展開のための機能

## 前書き

PHPでは`xxxxx($yyy)`のような式が函数呼び出しである… とは限らない。

ほかの言語でも `if($yyy) zzzzz();`のような構文があるが、PHPには「あたかも函数のように擬態した、函数ではないもの」が際だって多いように感じる。

その最たるものが`list()`であり、初めて見たときには筆者も目を疑った。

```php
<?php
list($x, $y) = array(1, 2);
```

`list`と`array`のどちらも、函数呼び出しではない。

### PHP 7.1以降では

まったく同じ意味を短く書けます。

```php
<?php
[$x, $y] = [1, 2];
```

## PHPの配列(array)

PHPの配列は、その名前に反して、実に多様な機能を併せ持った[データ型](https://ja.wikipedia.org/wiki/%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B)です。

> PHP の配列は、実際には順番付けられたマップです。マップは型の一種で、 値をキーに関連付けます。 この型は、さまざまな使い道にあわせて最適化されます。 <mark>_配列_</mark>としてだけでなく、<mark>_リスト_</mark> (<mark>_ベクター_</mark>)、 <mark>_ハッシュテーブル_</mark> (<mark>_マップ_</mark>の実装の一つ)、<mark>_辞書_</mark>、<mark>_コレクション_</mark>、<mark>_スタック_</mark>、 <mark>_キュー_</mark>等として使用することが可能です。 PHP の配列には他の PHP 配列を値として保持することができるため、 非常に簡単にツリー構造を表現することが可能です。
>
> *php.net, [PHP: 配列 - Manual](http://php.net/manual/ja/language.types.array.php), 2014年8月12日閲覧. 引用は@tadsanによる.*

以上のように、数多くのデータ構造の機能を兼ねて持ちます。[大クラス主義を標榜する](http://www.atmarkit.co.jp/news/200712/25/ruby.html)[RubyのArray](http://docs.ruby-lang.org/ja/2.1.0/class/Array.html)よりも、さらに大ざっぱです。

これだけの機能を持つ配列さんですが、さらにもうひとつ、タプルの役割も持って居ます。

## 多値

PHPやRubyを含めたいくつものプログラミング言語では、函数には引数としていくつもの値を渡すことができますが、*返り値は常にひとつ* です。

一方で、函数からひとつだけでなく、複数の値を返したい需要があります。また、任意の個数の引数を受けるのに返り値がひとつしかないのは「非対称」であるようにも感じられます。

函数がいくつもの値を返すことを、いくつかのプログラミング言語では **多値**(*Multiple Values*) と呼びます([多値論理](https://ja.wikipedia.org/wiki/%E5%A4%9A%E5%80%A4%E8%AB%96%E7%90%86);[Many-valued logic](https://en.wikipedia.org/wiki/Many-valued_logic)は別物)。多値を実現するプログラミング言語にはGoやLua, Scheme, Common Lispなどがあります。

## タプル

**タプル**(*tuple*)または**組**とは、 **いくつのも値を組み合せた値** のことです。これを使って多値を実現するプログラミング言語もいくつもあります。

例として、「**ジュースの名前**を渡すと**メーカー名**と**値段**と**在庫数**が返ってくる函数」があったとします。このようなときに函数を返り値をどのようなデータとして表現するかにはいくつかの方法がありますが、ひとつの方法はタプルを返すことです。

(以下のコードはPythonで書いたサンプルコードですが、わざと回りくどく書いてます)

```python
def vendor(drink_name):
    """自動販売機"""
    #
    # なんかいろいろ処理がある
    #
    val = (maker, price, stock_quantity)
    return val

drink_tup = vendor("十六茶")
print(drink_tup)
# ('シャンソン化粧品', 150, 24)

maker          = drink_tup[0] #=> シャンソン化粧品
price          = drink_tup[1] #=> 150
stock_quantity = drink_tup[2] #=> 24
```

このプログラムで大切なのは、「0番めはメーカー名」「1番めは値段(円)」「2番めは在庫数」と、 **タプルの中の位置には意味がある** といふことです。

PHPやCなどのプログラミング言語にも、タプルに近い概念があります。それは **引数リスト** です。

```php
<?php
function trapezoid($height, $top, $bottom)
{
    return (($top + $bottom) / 2) * $height;
}

$top = 10;
$bottom = 15;
$height = 6;

echo trapezoid($height, $top, $bottom);
```

このようなプログラムを利用するとき、引数の順番は非常に重要です。うっかりと `echo trapezoid($top, $bottom, $height);` と書いてしまったら、間違った結果が表示されることになります。これがタプルの考へかたです。

> #### 備考
> タプルの実装は、言語によって大きく異なります。Pythonの`tuple`型は、一見して単なる変更不可能な配列のように見えます。また、OCamlやF#のタプルは特定の型ではなく、 `(int * int * int)` のように、含まれる値(要素)の集まりとして個別の型がつきます。(この記事の趣旨ではないので省きますが、`("apple", 30)`と`("apple", "30")`は別の型です)

### PHPでの多値

さきほどのPythonの自動販売機コードをPHPバージョンに直してみます。PHPにおいても`array`を使って複数の返り値を表現するパターンに知られて居ります([PHP: 返り値 - Manual](http://php.net/manual/ja/functions.returning-values.php))。

```php
<?php
/**
 * 自動販売機
 */
function vendor($drink_name)
{
    //
    // なんかいろいろ処理がある
    //
    $val = array($maker, $price, $stock_quantity);
    return $val;
}

$drink_tup = vendor("十六茶")
var_export(drink_tup);
// array (
//   0 => 'シャンソン化粧品',
//   1 => 150,
//   2 => 15,
// )

$maker          = $drink_tup[0]; //=> シャンソン化粧品
$price          = $drink_tup[1]; //=> 150
$stock_quantity = $drink_tup[2]; //=> 24
```

もう説明がめんどくさくなったのでサンプルコードだけ出して一気に片付ける。あとはわかるな?

```php
<?php
/**
 * 自動販売機
 */
function vendor($drink_name)
{
    //
    // なんかいろいろ処理がある
    //
    return array($maker, $price, $stock_quantity);
}

list($maker, $price, $stock_quantity) = vendor("十六茶");

echo $maker;          //=> シャンソン化粧品
echo $price;          //=> 150
echo $stock_quantity; //=> 24
```

## まとめ

 * 実際、[PHP: 返り値 - Manual](http://php.net/manual/ja/functions.returning-values.php)の内容を、周辺について説明しつつ、迂遠に書いただけだ
 * PHPの`list()`を初めて見たときはPHPの歪んだ構文設計の象徴のように感じたが、今は愛しい
 * この記事はPHPを使って説明したが、Rubyも大クラス主義によりタプルは存在しないので、同様に配列を利用する
 * この記事はPHPを使って説明したが、Pythonの`tuple`について「イミュータブルな配列」のような認識をしてたら改めてほしい
 * サンプルコードのPythonのコードは、わざと冗長に書いた
   * 当然Pythonには`list()`のような構文は存在しない
   * `maker, price, stock_quantity = vendor("十六茶")` と書くだけ。簡潔！
   * ちなみにPythonの[list](http://docs.python.jp/3.4/library/stdtypes.html#list)([チュートリアル](http://docs.python.jp/3.4/tutorial/introduction.html#lists))は数値のキーのみからなる配列のようなデータ構造である
 * OCaml, F#のような言語はタプルをスマートに分解する言語構造がいくつもある
   * これらの言語の函数は「引数と返り値は必ずひとつづつ」とすることで対称的である

<hr />
<br /><br /><br /><br />

## 別案

各位知っての通り、このようなパターンも存在し、`list`を使ったパターンとどちらが適するかは、実際のところケースバイケースである。読者各位の懸命な判断に任せる。

```php
<?php
/**
 * 自動販売機
 */
function vendor($drink_name)
{
    //
    // なんかいろいろ処理がある
    //
    return array(
        'maker' => $maker,
        'price' => $price,
        'stock_quantity' => $stock_quantity
    );
}

$drink = vendor("十六茶");

echo $drink['maker'];          //=> シャンソン化粧品
echo $drink['price'];          //=> 150
echo $drink['stock_quantity']; //=> 24
```

以上。

### 別案の2018年追記

PHP 7.1以降では連想配列も受け取ることができる。 ⇒ [PHP7.1新機能: `list()` におけるキーのサポート](http://php.net/manual/ja/migration71.new-features.php#migration71.new-features.support-for-keys-in-list)

```php
[
    'maker' => $maker,
    'price' => $price,
    'stock_quantity' => $stock_quantity,
] = vendor("十六茶");

echo $maker;          //=> シャンソン化粧品
echo $price;          //=> 150
echo $stock_quantity; //=> 24
```