閑古鳥

オールドプログラマの日記。プログラミングとか病気(透析)の話とか。

可変長引数をとる関数に配列を渡したい(PHP/JavaScript)

PHPで:

<?php
$data = [1, 2, 3, 4, 5];
pack("l*", $data);
#=> 20byteのバイナリがほしいのに、4byteしか取れない
?>

なんてことをやってしまった。pack関数の第二引数は可変長配列ですが、配列を渡すとその配列オブジェクトのバイナリが返ってきてしまいます。C言語でprintfに配列を渡すようなことは普通しないと思いますが、なんとなくPHPはうまくやるんじゃないかと思ってしまったんですよね…。

<?php
$data = [1, 2, 3, 4, 5];
pack("l*", ...$data);
?>

今回のようなケースでは上記のように書けば期待通りの動きになります。

PHPの "..." は名前付いてないんでしょうか。検索してもよくわかりませんでした。マニュアルには"...トークン"と書いてあるけど口頭ではなんと発言するんだろう。

JavaScriptではスプレッド構文と呼ぶみたいですね。同じような使い方をします。Math.max関数なんかが可変長引数を取り、

Math.max(1, 2, 3); // => 3

などと書けますが、配列を渡すとうまくいかず、スプレッド構文を使う必要があります。

Math.max([1, 2, 3]); // => NaN
Math.max(...[1, 2, 3]); // => 3

思い返すとC#でも似たようなやらかしをしたなぁ。DataTableを使っているときに、行を追加するメソッドが可変長引数を取るので行の要素を配列で突っ込んだら最初の列に配列オブジェクトが表示されるというやつ。

var dt = new DataTable();
dt.Columns.Add("A");
dt.Columns.Add("B");

dt.Rows.Add(1, 2); // OK
dt.Rows.Add(new int[] { 1, 2 }); // NG

このメソッドはobject[]を取るので

dt.Rows.Add(new object[] { 1, 2 });
// とか、
var array = new int[] { 1, 2 };
dt.Rows.Add(array.OfType<object>().ToArray());

みたいに書けば動くには動くんですが…。まぁ、素直にRow作ってから列を設定する方が良さそうですね。