PHPのarray_combineを自作関数で遊んで実装

# はじめに

少し前にPHPのarray系の組込み関数を自作関数で作って遊んで書いてた時があり最近、久しぶり遊んでみました。脳トレになるし、他にもいろいろな書き方を思いついて実装出来ます。さらに、こんな組込み関数あったんだってなるのでかなりいいと思うので今回は、`array_combine`を自作関数で実装してみます。

皆さんも是非この記事を読み終わった後に、組込み関数を自作関数で作成してみて遊んでみてください。


#目次
1. array_combine仕様
2. for文 実装
3. 再帰関数 実装
4. 再帰関数+ポインタ操作+参照渡し 実装
5. 再帰関数+ポインタ操作+参照渡し+高階関数+コールバック関数 実装
6. 最後に

# array_combine仕様

まず最初に[公式](https://www.php.net/)のページで`array_combine`の仕様について見てみましょう。

```php
array_combine ( array $keys , array $values ) : array
```
> keys 配列の値をキーとして、また values 配列の値を対応する値として生成した 配列 を作成します。
>> 引用元　https://www.php.net/manual/ja/function.array-combine.php

第一実引数にkeyにしたい配列を指定し、第二実引数にvalue値にしたい配列を指定すると、key => valueで配列を作成してくれるというこですね。

例

```php
$a = array('green', 'red', 'yellow');
$b = array('avocado', 'apple', 'banana');
$c = array_combine($a, $b);

print_r($c);
//Array
//(
//    [green]  => avocado
//    [red]    => apple
//    [yellow] => banana
//)

```

上記の様な配列が完成します。for文を使用せずに作成出来るのですっきりしますね。

今回前提として
エラーが発生する時の例外処理は無視します。
使用するデータは、例で使用したデータをそのまま使用します。
自作関数に渡す配列の第一実引数,第二実引数は同じ数にします。

# for文 実装

まず、最初はfor文で実装をしてみます。

```php
function _array_combine($array_keys, $array_values) {
    $result = [];
    for ($i = 0; $i < count($array_keys); $i++) {
        $result[$array_keys[$i]] = $array_values[$i];
    }
    return $result;
}

$c = _array_combine($a, $b);
print_r($c);
```

ポイントは、どのように第一実引数をkey、第二実引数をvalueに設定するかだと思います。今回は、受け取った配列を`count`関数を使用して回数分for文を回し
`$result[第一実引数の値をkeyに設定]=ここに第二実引数の値をvalueに設定`
といった風に実装します。

次に、再帰関数で実装します。

# 再帰関数 実装

再帰関数で実装するので、まず最初にどのようにして戻ってこれるかを考えていきます。戻ってこれる処理を書かない場合、処理が実行し続けることになってしまいます。

下記の処理は再帰関数の例です。

```php

// helloが2回出力されて処理が終わる
$num1 = 0;
function recursion($num2) {
    echo 'hello';
    $num2++;
    if ($num2 !== 2) {
        recursion($num2);
    }
    return;
}

recursion($num1);

```
`$num2`が2の時以外は実行される処理なので`$num2`が2の時には上に戻ってこれるので処理が止まります。

それを念頭に置いて、`array_combine`を再帰関数で実装したのが下記の処理です。

```php
function _array_combine($array_keys, $array_values) {
    $result = [];
    $result[$array_keys[0]] = $array_values[0];
    array_shift($array_keys);
    array_shift($array_values);
    if (count($array_keys) > 0) {
        $result = array_merge($result, _array_combine($array_keys, $array_values));
    }
    return $result;
}

$c = _array_combine($a, $b);
print_r($c);
```

`array_shift`を使用して配列の先頭を削除します。`index`は0からまた割り振られます。
そしてここで、ポイントになる上に戻ってこれる処理を書きます。`$array_keys`の配列が0以上の時はまだ作成が終わってないということなので関数をもう一度実行します。0になった時に、上に戻ってこれるようにします。

次に、再帰関数+ポインタ操作+参照渡しを実装します。

# 再帰関数+ポインタ操作+参照渡し 実装

```php
function getNextValue(&$array_keys1, &$array_values1) {
    $value1 = current($array_keys1);
    $value2 = current($array_values1);
    next($array_keys1);
    next($array_values1);
    return [$value1, $value2];
}

function isEndValue($array_keys2, $value2) {
    return end($array_keys2) === $value2;
}

function _array_combine($array_keys, $array_values) {
    $result = [];
    $array = getNextValue($array_keys, $array_values);
    $result[$array[0]] = $array[1];
    if (!isEndValue($array_keys, $array[0])) {
        $result = array_merge($result, _array_combine($array_keys, $array_values));
    }
    return $result;
}

$c = _array_combine($a, $b);
print_r($c);

```

ポイントになる部分としては、参照渡しとポインタ操作になると思います。

```php
function getNextValue(&$array_keys1, &$array_values1) {
    $value1 = current($array_keys1);
    $value2 = current($array_values1);
    next($array_keys1);
    next($array_values1);
    return [$value1, $value2];
}
```

上記の処理では、`$array_keys`と`$array_values`を参照渡しで渡してます。受けっとた仮引数の`$array_keys1`と`$array_values1`を`current`を使用して配列内の現在のポインタにある値を取得しています。

currentの仕様

```php
current ( array|object $array ) : mixed
```
> 各配列は、"カレント"の要素へのポインタを有しています。 このポインタは、配列に挿入された最初の要素を指すように初期化されます。
>> 引用元　https://www.php.net/manual/ja/function.current.php

次に`next`を使用して、配列内部のポインタを進めます。

nextの仕様

```php
next ( array|object &$array ) : mixed
```
> next() は、ひとつの違いを除いて current() と同じです。 next() は要素を返す前に内部配列ポインタをひとつ先に進めます。 つまり、次の配列要素を返すとともに内部配列ポインタをひとつ進めるということです。
>> 引用元　https://www.php.net/manual/ja/function.next.php

最後に、`key`と`value`になる値を返します。

次に下記の関数が呼び出されます。

```php

function isEndValue($array_keys2, $value2) {
    return end($array_keys2) === $value2;
}
```

`$array_keys`を実引数で渡してあげ、その配列のポインタを最後の要素に設定して現在の配列の値が最後の要素と一致した場合は、上に戻ってくるようにするので`_array_combine`を実行しません。

endの仕様

```php
end ( array|object &$array ) : mixed
```
> end() は array の内部ポインタを最後の要素まで進め、その値を返します。
>> 引用元　https://www.php.net/manual/ja/function.end.php


次に、再帰関数+ポインタ操作+参照渡し+高階関数+コールバック関数で実装します。

# 再帰関数+ポインタ操作+参照渡し+高階関数+コールバック関数 実装

```php
function getNextValue(&$array_keys1, &$array_values1) {
    $value1 = current($array_keys1);
    $value2 = current($array_values1);
    next($array_keys1);
    next($array_values1);
    return [$value1, $value2];
}
function isEndValue($array_keys2, $value2) {
    return end($array_keys2) === $value2;
}
function _array_combine($array_keys, $array_values, $callback) {
    $result = null;
    $array = getNextValue($array_keys, $array_values);
    $result = $callback($array);
    if (!isEndValue($array_keys, $array[0])) {
        $result = array_merge($result, _array_combine($array_keys, $array_values, $callback));
    }
    return $result;
}

$callback = function($array1) {
    return [$array1[0] => $array1[1]];
};

$c = _array_combine($a, $b, $callback);
print_r($c);
```

ここでは、そこまで詳しく説明する部分は無いのですが、コールバック関数を作成し引数に追加してあげます。

正直、ここまでくるとあんまり使っている意味が無くなってくると思うのですが、この自作関数にPHPの沢山の機能を詰め込むことが出来るので出来た時の達成感はあります(笑)

# 最後に

いかがだったでしょうか、どんどん自分で制約を決めていくとさらに厳しくなっていきます。例えば、PHPにある組込みの関数を一切使わずに自作関数だけて実装してみるとかです。大変なのですがめちゃくちゃ楽しく出来ると思うので是非やってみて下さい。