LoginSignup
41
15

More than 3 years have passed since last update.

PHPで分割代入していくだけの投稿

Last updated at Posted at 2019-11-30

この記事は PHP Advent Calendar 2019 の1日目の記事です。

分割代入とは

配列の中身を複数の変数に一回で代入できる書き方

list()[]

list()を使うか、PHP7.1以降では[]を使ってもOK

この投稿では基本的に[]の書き方で試していきます。

$colors = ['red', 'yellow', 'blue'];

[$x, $y, $z] = $colors;
var_dump($x, $y, $z); // "red", "yellow", "blue"

list($a, $b, $c) = $colors;
var_dump($a, $b, $c); // "red", "yellow", "blue"

swapした例

$a = 'apple';
$b = 'banana';

[$a, $b] = [$b, $a];
var_dump($a, $b); // "banana" "apple"

list($a, $b) = [$b, $a];
var_dump($a, $b); // "apple" "banana"

// 関数を用意する例
// 参考:https://www.php.net/manual/en/migration71.new-features.php
function swap(&$a, &$b): void {
    [$a, $b] = [$b, $a];
}
swap($a, $b);
var_dump($a, $b); // "banana" "apple"

keyを指定してできる

list()でキーを指定するやり方はPHP7.1から

$animals = ['dog' => 'イヌ', 'cat' => 'ネコ'];

['dog' => $dog1, 'cat' => $cat1] = $animals;
var_dump($dog1, $cat1); // "イヌ" "ネコ"

list('dog' => $dog2, 'cat' => $cat2) = $animals;
var_dump($dog2, $cat2); // "イヌ" "ネコ"

注意点

一回はまった部分なのですが、配列をソートなどした場合に、インデックスを振り直さないと思い通りに動いてくれない時がありました

// 下2つの例は同じ意味で代入される
[$a, $b] = ['aaa', 'bbb'];
var_dump($a, $b); // "aaa", "bbb"
[$c, $d] = [0 => 'ccc', 1 => 'ddd'];
var_dump($c, $d); // "ccc", "ddd"

// 配列をソートしたがインデックスが変わってないなどの場合に、このような配列になったとすると
[$z, $y] = [1 => 'zzz', 0 => 'yyy'];
// $zに "yyy"、$yに "zzz" が代入された状態になってしまう!
var_dump($z, $y); // "yyy", "zzz"

// やり方はいろいろあると思いますが、
// array_values などで インデックスが振り直された状態にするとうまくいきました。
[$z, $y] = array_values([1 => 'zzz', 0 => 'yyy']);
var_dump($z, $y); // "zzz", "yyy"

代入する変数が少ない場合

[$a, $b] = [10, 20, 30, 40, 50];
var_dump($a, $b); // 10 , 20

[, $a, , , $b] = [10, 20, 30, 40, 50];
var_dump($a, $b); // 20 , 50

['blue' => $blue] = ['red' => '赤', 'blue' => '青'];
var_dump($blue); // 青

配列のキーが存在しない場合

[$a, $b] = [10];
var_dump($a, $b); // 10, NULL

[5 => $c] = [10]; // Notice: Undefined offset: 5

['a' => $aaa] = ['b' => 'bbb']; // Notice: Undefined index: a

ネストできる

[[$a, $b], [$c, $d]] = [[1, 2], [3, 4]];
var_dump($a, $b, $c, $d); // 1, 2, 3, 4
$config = ['db' => [
    'connection' => 'mysql',
    'host' => 'localhost',
    'database' => 'sample',
    'user' => 'root',
    'pass' => 'root',
]];

['db' => [
    'connection' => $connection,
    'host' => $host,
    'database' => $database,
    'user' => $user,
    'pass' => $pass,
]] = $config;

var_dump($connection, $host, $database, $user, $pass); // "mysql" "localhost" "sample" "root" "root"

foreach

$foods = [
    ['apple', 'tomato', 'cherry'],
    ['banana', 'orange', 'paprika'],
];
foreach($foods as [$food1, $food2, $food3]) {
    var_dump($food1, $food2, $food3);
}

$foods = [
    [
        ['apple', 'cherry'],
        ['tomato'],
    ],
    [
        ['banana', 'orange'],
        ['paprika'],
    ]
];
foreach($foods as [[$fruit1, $fruit2], [$vegetable1]]) {
    var_dump($fruit1, $fruit2, $vegetable1);
}
$todos = [
    [
        'id' => 1, 
        'is_done' => true, 
        'todo' => '買い物',
    ],
    [
        'id' => 2, 
        'is_done' => false, 
        'todo' => '映画',
    ],
];
foreach($todos as ['id' => $id, 'is_done' => $isDone, 'todo' => $todo]) {
    var_dump($id, $isDone, $todo);
}

$todos = [
    [
        'id' => 1, 
        'is_done' => true, 
        'todo' => [
            'shopping' => 'コンビニ',
        ],
    ],
    [
        'id' => 2, 
        'is_done' => true, 
        'todo' => [
            'shopping' => '百均',
        ],
    ],
];
foreach($todos as ['todo' => ['shopping' => $shopping]]) {
    var_dump($shopping);
}

配列の形でも代入できる

$todos = [
    [
        'id' => 1, 
        'is_done' => true, 
        'todo' => '買い物',
    ],
    [
        'id' => 2, 
        'is_done' => false, 
        'todo' => '映画',
    ],
];

$ids = [];
foreach($todos as $todo) {
    ['id' => $ids[]] = $todo;
}
var_dump($ids); // [1, 2]

クラスでも分割代入する

クラスで分割代入しようとすると、このようにエラーになるのですが、

class A {
    public $hoge = 'hoge';
}

['hoge' => $hoge] = new A; // PHP Fatal error:  Uncaught Error: Cannot use object of type A as array
var_dump($hoge);

ArrayAccessインターフェースを実装することで、クラスでも分割代入することができました。

参考:ArrayAccess,IteratorAggregateインタフェースで配列操作可能なオブジェクトを作成する - qiita

※↓実装の内容はLaravelのCollectionクラスをパクりました。

<?php

class A implements ArrayAccess
{
    private $items = [];

    public function __construct(array $values = []) {
        $this->items = $values;
    }

    public function offsetExists($offset)
    {
        return array_key_exists($offset, $this->items);
    }

    public function offsetGet($offset)
    {
        return $this->items[$offset];
    }

    public function offsetSet($offset, $value)
    {
        if (is_null($offset)) {
            $this->items[] = $value;
        } else {
            $this->items[$offset] = $value;
        }
    }

    public function offsetUnset($offset)
    {
        unset($this->items[$offset]);
    }
}

// ArrayAccessインターフェースを実装すると、クラスを配列のように扱うことができる
$A1 = new A;
$A1[0] = 'hoge';
var_dump($A1[0]); // "hoge"

// 分割代入もできました!
$A2 = new A(['a', 'b', 'c']);
[$a, $b, $c] = $A2;
var_dump($a, $b, $c); // "a" "b" "c"

$A3 = new A(['dog' => '犬', 'cat' => '猫', 'mouse' => 'ネズミ']);
['dog' => $dog, 'cat' => $cat, 'mouse' => $mouse] = $A3;
var_dump($dog, $cat, $mouse); // "犬" "猫" "ネズミ"

参考


最後まで見ていただいてありがとうございました。m(_ _)m

41
15
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
15