PHPには可変関数というものがあるが、これは変数に格納された文字列を関数名として展開してくれる機能だ。
これを使用すれば、後から文字列を使って関数を呼び出せる事になる。
例えば

$str = "foo";
function foo($a) {
  echo $a;
}
$str("Hello");

とすれば"Hello"という出力を得る。 同じような事が出来る関数でcall_user_funcというのもある。

call_user_func("foo","Hello");

とすれば同様に"Hello"という出力を得る。
さらに柔軟なcall_user_func_arrayという関数もある。
書き方はこんな感じだ。

call_user_func_array("foo", $Array);

使い方はcall_user_funcとほとんど同じだが第二引数に配列を指定する。
ただし実際はその配列の要素は展開されて第一引数で指定した関数に渡されることになる。
なので

call_user_func("foo","Hello", "world", "!");

call_user_func_array("foo", array("Hello", "world", "!"));

は同じ事をしている。引数が可変の関数を呼び出す時に便利だ。
例えばコマンドラインでPHPファイルを呼び出す時に第一引数に関数名を、以降の引数はすべてその関数に渡して処理したいといった時に

#!/opt/local/bin/php
<?php
call_user_func_array($argv[1], array_slice($argv, 2));
function func() {
  $a = func_get_args();
  echo join("\n", $a);
}
?>

こんなコードを書く事が出来る。
呼び出すときはターミナルから

sample.php func Perl PHP Python Ruby Javascript

等とすれば

Perl
PHP
Python
Ruby
Javascript

という結果が得られる。
最初の引数に指定する関数が存在しなければエラーになってしまうが、その値を変える事によってどの関数を呼び出すかを指定できるようになる。

Rubyにはsendというメソッドがあり同様の目的で使える。
コードは

#!/opt/local/bin/ruby
def func(*a)
  print a.join("\n")
end
send(ARGV.shift, *ARGV)

こんな感じだが、これを同じように

sample.rb func Perl PHP Python Ruby Javascript

とターミナルから呼び出せば同様の出力になるはずだ。
これはsendメソッドの第一引数にメソッド名(この場合はfunc)を指定し同じく以降の引数をそのメソッドに渡している。
ここでもARGVの前にアスタリスクを付ける事によって配列ARGVを展開した状態で渡している。

PerlやPythonはどうだろうか?

Perlにはシンボリックリファレンスという機能があってこれを使えばPHPの可変関数の様な事が出来る。
コードはこんな感じだ。

$str = "foo";
sub foo {
  print shift;
}
$str->("Hello");

ただしこのシンボリックリファレンスはいろんな理由で非推奨となっている。
スクリプトファイルの中でuse strictしていた場合は使えない。
やはり非推奨となっているものを使うのは気が咎めるので使わないようにしよう。
がんばればPerlでも、そしてPythonでも上のようなスクリプトを作成できる。
それぞれコードは

Perl:

#!/opt/local/bin/perl
use strict;
use warnings;
$::{$ARGV[0]}(@ARGV[1..$#ARGV]);
sub func {
  local $" = "\n";
  print "@_\n";
}

Python:

#!/opt/local/bin/python
import sys
def func(*y):
  print "\n".join(y)
vars()[sys.argv[1]](*sys.argv[2:])

こうなる。 そしてターミナルから

sample.pl func Perl PHP Python Ruby Javascript
sample.py func Perl PHP Python Ruby Javascript

同様の出力になったはずだ。

ところでそれぞれの言語にデフォルトのコマンドライン引数があるが(大抵ARGVとか@ARGVとか$argvとか・・・)、PerlやRubyはその配列にファイル名は含まれていない。 PythonとPHPは最初の要素がスクリプトファイル名になっているのでちょっと注意。

カテゴリ:

トラックバック(0)

トラックバックURL: http://blog.beanz-net.jp/beanz_mtos/mt-tb.cgi/27

コメントする