AnDeriensのブログ

個人的なブログです

PHPにおける3点リーダ

関数の引数に... を使うことができるようで、どういう使い方ができるのかよくわかっていなかったので調べた。

バージョン

PHP5.6以降。*1

以下の実行環境は PHP 7.3.7

関数の引数

3点リーダを使うケースには2パターンある。

  1. 可変長引数

  2. 引数のアンパック

可変長引数

関数の定義時に3点リーダを使うと、引数を配列に入れてくれる。

<?php
function myFunc (...$args)
{
    var_dump($args);
}

$args = [1,2,3];

myFunc($args);

# array(1) {
  [0]=>
  array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    int(3)
  }
}


myFunc(1, 2, 3);

# array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}

引数のアンパック

逆に、呼び出し時に3点リーダを使うと、配列を展開してくれる。

<?php
function myFunc2($a, $b, $c)
{
    echo "$a / $b / $c";
}

$args = [1, 2, 3];

myFunc2(...$args);

# 1 / 2 / 3

アンパックとタイプヒンティング

タイプヒンティングもできる。 ただ、定義時に型指定バッチリしておいて、呼び出し側を配列にするメリットが今の所思い浮かばない。

<?php

class Name
{
    private $true_name;
    public $false_name;

    public function __construct(string $oracle)
    {
        $this->true_name = $oracle;
        $this->false_name = sha1($oracle);
    }

    public function __toString()
    {
        return $this->false_name;
    }
}

class Persona
{
    private $persona;

    public function __construct(...$elements)
    {
        $this->persona = $elements;
    }

    public function express()
    {
        return implode(',', $this->persona);
    }
}

class Truth
{
    private $idea;

    public function __construct(string $idea)
    {
        $this->idea = $idea;
    }

    public function express()
    {
        return '';
    }
}

class Subject
{
    private $name;
    private $persona;

    public function __construct(Name $name, Persona $persona)
    {
        $this->name = $name;
        $this->persona = $persona;
    }

    public function selfIntroduction()
    {
        echo "Hey, i'm $this->name. my property is expressed by " . $this->persona->express();
    }
}

$name = new Name('Anderiens');
$persona = new Persona('male', 'engineer', 'smart');
$truth = new Truth('Cogito, ergo sum.');

とクラス定義をした上で、

<?php
$anderiens1 = new Subject(...[$name, $persona]);
$anderiens2 = new Subject(...[$persona, $name]);
$anderiens3 = new Subject(...[$name, $truth]);

$anderiens1->selfIntroduction(); // Hey, i'm 9f2ee80b1cc40f738b0acb6305070f994be4dee0. my property is expressed by male,engineer,smart
$anderiens2->selfIntroduction(); // PHP Fatal error:  Uncaught TypeError: Argument 1 passed to Subject::__construct() must be an instance of Name
$anderiens3->selfIntroduction(); // PHP Fatal error:  Uncaught TypeError: Argument 2 passed to Subject::__construct() must be an instance of Persona

付録

PHP7.4以降だと、さらに配列のアンパック機能が追加になるとのこと。

Spread Operator for Arrays Coming to PHP 7.4 - Laravel News