タグ別アーカイブ: PHP

PHP5.5のリリースに合わせて、php.netをリニューアルしたそうな

いつも大変お世話になっております、php.net。久しぶりにじっくりと舐め回すように眺めたら、ページの頭の部分に”Step into the future! Click here to switch to beta php.net site”という文字が書かれている。どうせスパムリンクだろうと思って迷わずクリックしたら、php.netのリニューアルヴァージョンが出てきた。

PHPのヴァージョンも5.5でキリが良いし、php.netもいっちょリニューアルしておくかということらしく、今後はリニューアル後も一向にあか抜けない見た目の、新ヴァージョンに切り替えるらしい。なにこれ、jQuery(おまけにjQuery UIまで!)とか使ってしまって、PHPerとしては軟派になったphp.netを許せない!静的サイトで作り直せ!

ということを愚痴っても仕方が無いので、PHP5.5まわりについて言及しておこう。PHP5.5がリリースとなった事で、決まり通り2ヴァージョン前の5.3のサポートが打ち切られるということになるはずだけど、結局1年間は延長サポートになるらしい。

大抵のレンタルサーバって、PHPのヴァージョン5.2.8か5.3.6かを選ばせている段階だろうから、サポートが少し伸びた事は朗報だろうか。5.4が嫌悪されたということなのかねぇ。

PHP5.5では、cURLがHTTP Pipeliningに対応した。つまりこれまで作ったプログラムを通信部分が高速なものに書き直せるということで、非常に興味があるのだけれど、これまで作ったプログラムはまだ5.4の壁を越えられていないので…

まず5.4の変更点を慌てて読み返す作業にとりかからねば。


PHP、JavaScriptそれぞれにおける無名関数

PHPとJavaScriptを同時に使って開発を行う事が多いという個人的事情のため、混同しないようにする目的で書いているこの比較シリーズですが、今回は無名関数について扱います。

無名関数というのは、関数的な処理のまとまりを、名前空間を消費することなくアドホックに定義する手法で、最近ではajaxなどの通信を伴う関数の、コールバック関数として使われるのが一番身近な使用と言えるかもしれません。無名関数使用例の紹介もかねて、PHPとJavaScriptそれぞれの無名関数の書式を見てみましょう。

PHPにおける無名関数

基本的な書式

以前、spl_autoload_register関数の説明で用いた例です。

//無名関数の登録
spl_autoload_register(function($classname){
include $classname . ".class.php";
});

なにやらjQuery方面でよく見かけそうな、中括弧と小括弧の連続です。
無名関数を使っているのはspl_autoload_register関数の引数の部分で、したがってfunctionの前の”(“と最後の”)”は、無名関数の書式とは関係ありません。つまり、通常の関数定義を関数名を抜かして行えば無名関数になるわけですね。

無名関数の即時実行

なお、定義した無名関数に値を与えて即時実行する場合、可変長引数を関数内で引き渡す記事の際に使ったcall_user_func_array関数、もしくはcall_user_func関数を使います。

//無名関数の即時実行
//call_user_func(関数名,引数)という書式でしたね。
 
call_user_func(function($classname){
include $classname . ".class.php";
},"dullFunction");

PHPの無名関数の注意点としては、無名関数が使用可能なヴァージョンが5.3以降と、比較的最近実装された機能だという事です。現在稼働中のプログラムでも、5.2系のヴァージョンで作成され今まで運用されているものが結構ありますので、その場合無名関数は使えないので注意です。

JavaScriptにおける無名関数

基本的な書式

JavaScriptを使ったajax開発では、無名関数が頻繁に登場します。以下はjQueryの$.ajaxでコールバックとして無名関数を登録する例です。

//ajaxコールバックとして無名関数の登録
$.ajax({
url : "test.html",
success : function(data){
$("#contents").append(data);
}
});

successのラベル以降が無名関数の使用になります。PHPのものと、変数に$が付くか付かないか程度の違いしかありません。

無名関数の即時実行

無名関数の即時実行について、JavaScriptは専用の関数を持っていません。かわりにより簡潔な書き方で即時実行をすることが出来るようになっています。

//無名関数の即時実行
(function(data){
$("#contents").append(data);
})(anydata);

通常の無名関数の宣言との違いは、関数名にあたる部分を括弧でくくり、また関数の実行なので最後にセミコロンをつけているだけです。

即時実行の利用頻度は低いかもしれませんが、ソースコードの中に急に出現した括弧付きの無名関数宣言に、当惑してしまわぬよう頭の片隅に入れておくとよろしいでしょう。


PHP5.1.2以降のspl_autoload_registerを使う

外部PHPファイルをインポートして呼び出そうとするとき、いちいちファイルの頭で読み込む数だけincludeを行うのは面倒くさいですね。それならば、使いそうなクラス・関数をfunctions.phpのような一ファイルにまとめてしまえば呼び出しが一回で済む、ということも考えつきますが、これだと一クラス一ファイルの原則に反する上、外部ライブラリを使用する場合などは結局インクルードが必要になり、上手く行きません。

そこで、PHP5以降のヴァージョンに搭載された便利なautoload機能を使いましょう。

PHP5以降の__autoload関数を使ったautoload

PHPには、マジックメソッドと呼ばれる”__(アンダーバー2つ)”から始まる特殊なメソッドがあります。たとえばPHPのクラスについてのエントリで出てきた、__construct。これは予約されたメソッド名なので、この名前を使ってオリジナルの関数を作ってはいけません。既にこの名前のメソッドには使用方法が決められているのです。__constructであれば、クラスのインスタンスが作られたときに呼び出される処理ということでしたね。

さて、autoload機能を実現する__autoloadは、クラスに紐づけられたメソッドというわけではなく、グローバル関数です。ですが、基本的にはマジックメソッドの一類であると考えて下さい。この関数は、未定義のクラスが呼ばれた際に自動的に呼び出されます。

<?php
//未定義のクラス
$instance = new undefinedClass();
?>

もしこの呼び出しの時点で、undefinedClass.phpをincludeしていなかったら、通常はメソッドが見つからないというエラーになります。一方、__autoloadを定義しておくことで、こうしたクラスの見つからないケースでの挙動を指定できます。

<?php
__autoload($classname){
include $classname . ".php";
}
?>

__autoloadは呼び出されたクラス名を引数としてとるので、それを適当な変数名で受けて、includeするファイルネームを生成する処理を書くのです。こうすることによって、クラスを作ったらクラス名.phpという名前に保存するようにすれば、呼び出し時に自動的に探し出してincludeしてくれます。

PHP5.1.2以降のspl_autoload_register関数を使ったautoload

ただ、__autoloadにも不便な点があります。それは、一度定義してしまうと、それ以外の__autoload処理を追加していくことが出来ないということです。__constructの例と同じように、こうした特別なメソッドは一度きりのタイミングに処理を登録することが許されているのです。そこで、複数のautoload処理(たとえば、優先順をつけて探索処理を追加したい場合)を登録するにはどうすれば良いか。そのような場合には、spl_autoload_register関数で処理を追加します。

//autoloadスタックに登録したい関数その1
function searchClassPhp($classname){
include $classname . ".class.php";
}
//autoloadスタックに登録したい関数その2
function searchPhp($classname){
include $classname . ".php";
}
 
//関数を両方ともautoloadスタックに追加
spl_autoload_register("searchClassPhp");
spl_autoload_register("searchPhp");

この例では、定義されていないundefinedClassが呼ばれたとき、最初にundefinedClass.class.phpというファイルが存在するかチェックされます。もし見つからない場合は、undefinedClass.phpが探されます。

ちなみに、spl_autoload_register関数を使ってしまうと、__autoloadで定義した処理は魔法が解けて無視されるようになってしまいます。そこで、__autoloadを定義しており、spl_autoload_register関数も使いたい場合には、__autoload自体もautoloadスタックに登録して下さい。

//魔法の解けた__autoloadを普通の関数として登録
spl_autoload_register("__autoload");

spl_autoload_register関数には、無名関数も登録することが出来ます。

//無名関数の登録
spl_autoload_register(function($classname){
include $classname . ".class.php";
});

ただし無名関数については5.3.0以降のヴァージョンに限定されます。だんだん便利になっているのか、母屋を継ぎ足し継ぎ足し増築しているのか、なんともPHPらしいですね。


クラスベース言語PHPの基本作法

オブジェクト指向のタイプ別分類によれば、JavaScriptが属するプロトタイプベース言語とは異なる、クラスベース言語に含まれるPHP。けれども、そもそもPHPという言語は場当たり的な書き方ができる言語としてブイブイ鳴らしていたもので、ゆえにPHP4以前のヴァージョンでのオブジェクト指向サポートは少し心許ないものでした。

2004年にリリースされたPHP5では、その辺りの弱さを解決し、Javaに近いクラスベースに移行しています。したがって、PHPでのクラスを使った開発の作法というのは、基本的にはJavaのそれに近いものになります。基本的な部分の書き方を見てみましょう。

クラスの宣言とアクセス制限

PHPの基本的なクラス宣言です。

//クラス宣言 someHowClass.php
class someHowClass{
 
//クラスプロパティ
public $somehow = "とにかく";
 
//メソッド
function someHowMethod(){
return "動け!";
}
 
}
 
//別ファイルからの呼び出し・インスタンス化・メソッドへのアクセス
require_once("someHowClass.php");
$somehow = new someHowClass();
echo $somehow->somehow . $somehow->someHowMethod();
 
//結果表示
とにかく動け!

クラス宣言をする場合、classという予約語を使います。クラスプロパティ・クラスメソッドの宣言は、通常の変数宣言や関数定義をclassの括弧内で行うことでできます。この際にプロパティ・メソッドへのアクセス制限を行うことも可能で、その場合に使う修飾子はJavaやSmalltalkと同じく、public、private、protectedがあります。

アクセス修飾子 アクセス可能な範囲
public(初期値) メソッド・プロパティをどこからでも呼び出し可能
private クラス内でのアクセスが可能
protected クラス内および子クラスからのアクセスが可能

コンストラクタ

インスタンスが作成される際の初期値を定義するコンストラクタは、__construct()という関数の処理として書きます。

//クラス宣言 someHowClass.php
class someHowClass{
 
//コンストラクタ
function __construct($value){
$this->value = $value;
}
 
//メソッド
function someHowGetValue(){
return $this->value;
}
 
}
 
//別ファイルからの呼び出し・インスタンス化・メソッドへのアクセス
require_once("someHowClass.php");
$somehow = new someHowClass("動け!");
echo $somehow->someHowGetValue();
 
//結果表示
動け!

コンストラクタの呼び出し時に引数を与えることで、インスタンスの初期値を設定することができます。なお、PHP4の時点でのクラスは、コンストラクタがクラス名と同名のメソッドでした。互換性の為に現在でも、__constructの宣言が無い場合には同名メソッドをコンストラクタとする仕様になっています。

クラスの継承と親クラスのメソッド・プロパティの参照

クラスの継承についても見てみましょう。

//クラス宣言 anyWayClass.php
class anyWayClass extends someHowClass{
 
//メソッドをオーバーライド
function someHowGetValue(){
return $value . "!";
}
 
//メソッドの追加
function anyWayGetValue(){
//親クラスのメソッドの参照
return parent::someHowGetValue();
}
 
}
 
//別ファイルからの呼び出し・インスタンス化
require_once("someHowClass.php");
require_once("anyWayClass.php");
$anyway = new anyWayClass("動け!");
 
//子クラスでオーバーライドしたメソッドの呼び出し
echo $anyway->someHowGetValue();
 
//結果表示
動け!!
 
//子クラスで宣言したメソッドの呼び出し
//(処理内容は親クラスのsomeHowGetValue()メソッドの呼び出し)
echo $anyway->anyWayGetValue();
 
//結果表示
動け!

継承をする場合には、extendsという予約語を使い継承元のクラスを指定します。親クラスのプロパティ・メソッドは自動的に子クラスにも実装されるため、上の例では子クラス内で宣言の無いコンストラクタ(__construct())についても処理が出来ています。
同名プロパティ・メソッドに、子クラスでは違う処理を充てたいという場合には、子クラス内で同名プロパティ・メソッドを宣言すると、そちらが呼び出し時に優先されるようになります。上の例ではsomeHowGetValue()メソッドをオーバーライド(上書き)したため、処理結果が親クラスと変わっています。

一方、子クラスで宣言したものではなく、親クラスのsomeHowGetValue()メソッドを呼び出したくなった場合には、parent::という語をつけて呼び出すことで、子クラス内から親クラスのプロパティ・メソッドの参照が出来ます。

なお、PHPの継承は多重継承を認めない仕様になっています。

PHPのクラスの基本はこのような感じです。その他にinterfaceの定義などもあるのですが、とりあえずは説明をここまでとします。

また、いままでオブジェクト指向に全く触れたことがないという人間にとってはチンプンカンプンな内容だったと思うので、オブジェクト指向の説明記事についてはいずれ改めて書かせていただこうと思います。


PHP、JavaScriptで可変長引数を、関数内で引き渡す

可変長引数が抱える心の闇

PHP、JavaScriptそれぞれの可変長引数サポートという記事で扱ったテクニック、可変長引数。関数定義でarg1,arg2,arg3…と続ける事無く、スマートに引数を取り出す事が出来ます。

しかしながら、引数にローカル変数を充てないという事は、関数内での引数の引き渡しで困難に出会います。

//PHP
function dullfunction(){
$args = func_get_args();
otherfunction($args);
}
 
//想定した動作をしてくれません。

動作が想定通りいかないのは、当たり前の事です。この書き方ですと、関数otherfunction()に配列$argsへの参照が与えられるだけで、したがってotherfunctionの中では$argsを参照した1つの引数が与えられたものと見なされてしまいます。

それならば、引数の一つ一つを$args[0],$args[1]…のように分けて渡せば良い!と思われるかもしれませんが、それは可変長引数という前提に忠実ではありません。

そこで、そもそも関数に引数として配列を渡せないのはおかしいと上司に叛旗を翻してみて下さい。数十社クビになった後、親切な上司が(もしいればですが)教えてくれます。

PHP、JavaScriptで配列を関数の引数として与える方法

PHP、JavaScriptともに、配列を要素分だけ引数として与える方法があります。

//PHP
function dullfunction(){
$args = func_get_args();
call_user_func_array("otherfunction", $args);
}

PHPでは、call_user_func_array()という関数を用います。第一引数には、関数の名前を指定します。このとき()はつけません。また、以下のように第一引数に無名関数をとる事も出来ます。

//PHP
function dullfunction(){
$args = func_get_args();
call_user_func_array(function(){$args2 = func_get_args(); print_r($args2);}, $args);
}
 
//無名関数の中でcall_user_func_array("dullfunction",$args2);とかやってはいけない

ところで、このcall_user_func_array()について、あちこちの説明でまるでユーザが定義した関数でないと動かないかのような誤解を与える表現をしていますが、別に普通の関数(var_dumpとか…)を与えても動いてくれます。便利ですよ。

お次はJavaScriptの場合です。

//JavaScript
function dullfunction(){
otherfunction.apply(this,arguments);
}

可変長だろうがそうでなかろうが、JavaScriptの引数がargumentsで取れるという事は既に説明しました。今回新しく登場したapplyというfunctionオブジェクトのメソッドは、メソッドを呼び出した関数の中の”this”キーワードに別の値を代入するという、火星人が作ったようなよくわからない働きをするメソッドですが、第二引数には配列またはオブジェクトで呼び出し元関数への引数を与える事が出来るようになっています。

//JavaScript
function.apply(引数1,引数2);
 
//引数1:関数内の"this"に充てるもの。ただ可変長引数を与えたいだけならthisを指定し
//この部分の働きを殺す。
//引数2:関数に与える引数

きっと親切に教えてくれる上司は火星人です。即刻辞表を突き付けましょう。


PHP、JavaScriptそれぞれの可変長引数サポート

PHP、JavaSciptの関数処理記述方法

PHPとJavaScriptでユーザ関数の定義をするとき、引数をもつ関数の場合には以下のような書式を用います。

//PHP
function dullfunction($arg1,$arg2){
return $arg1 + $arg2;
}
//JavaScript
function dullfunction(arg1,arg2){
return arg1 + arg2;
}

何の変哲も無い、プログラミング言語普遍の関数定義ですね。これは関数の引数が2つであると決まっている場合の書き方になります。arg1、arg2と書いているのが引数(argument)になります。

定義した関数の数より少ない引数を与える場合

上で例に挙げた関数では、そもそも処理内容的に引数が二つとも揃っていないとエラーになってしまいます。それならば、内部処理が2つの引数を必ずしも必要としない関数であれば、定義より少ない関数を与えても大丈夫なのか、という話ですが、PHPとJavaScriptの場合はそこら辺を柔軟に解決しています。

PHPの場合には、無視される可能性のある引数にデフォルト値を設定する事でエラーを抑えます。

//PHP
function dullfunction($arg1,$arg2=null){
return "ダルい";
}
 
dullfunction(); //これはエラー
dullfunction(100); //$arg1には100が与えられる。$arg2はnull。エラーにはならない。
dullfunction(100,200); //$arg1に100、$arg2に200が与えられる。エラーにはならない。

関数定義中の引数部分で代入が行えるPHPらしい(ある意味破天荒な)解決です。ただし、デフォルト値を与える引数は必ず与えない引数の後に書くようにしないといけません。

JavaScriptの場合、与えられた引数の数が関数定義より少なくても、全く問題がありません。

//JavaScript
function dullfunction(arg1,arg2){
return "ダルい";
}
 
dullfunction(); //問
dullfunction(100); //題
dullfunction(100,200); //ナシ

この辺が入門用言語としてポピュラーな理由かもしれません。WEB制作者の中には、JavaScriptは気付いたら使えるようになっていたという習得歴の方もいらっしゃるかもしれません。私もそうでした。

関数が受け付ける引数の数を無制限にしたいとき(可変長引数)

表題の通り、引数の数を無制限にしたい場合です。たとえば与えられた引数全ての和を求めるというのは、よくある処理です。

PHPの場合は、とりあえず引数を持たない関数として定義しておいて、関数内部から実際に与えられた引数にアクセスする関数を呼び出します。この、あらゆるものを関数として用意してしまうようなところがPHP的だと言えるのですが、まあそれはどうでも良い事ですね。

//PHP
function dullfunction(){
$sum = 0;
$num = func_num_args();
for($i=0;i<$num;$i++){
$sum += func_get_arg($i);
}
return $sum;
}
 
//もしくは…
function dullfunction(){
$sum = 0;
$arglist = func_get_args();
for($i=0;i<count($arglist);$i++){
$sum += $arglist[$i];
}
return $sum;
}
 
dullfunction(100,200...); //お好きな数どうぞ

func_num_args()という引数の数を返す関数と、func_get_arg()/func_get_args()という引数そのものをインデックス指定で/配列として 返す関数があります。

JavaScriptの場合、関数定義とは関数オブジェクトを作るということであり、関数オブジェクトには与えられた引数を自動的に格納するargumentsプロパティがあります。したがって、実は定義式での引数の数の宣言もへったくれも無いわけです。引数が何個来ようが、不真面目にargumentsプロパティにアクセスすればいいのです。

//JavaScript
function dullfunction(){
var sum = 0;
for(i=0;i<dullfunction.arguments.length;i++){
sum += dullfunction.arguments[i];
}
return sum;
}
 
dullfunction(100,200...); //お好きな数どうぞ

PHPもJavaScriptも、かなりゆるい言語であることがわかりましたね。そしてゆるさの性格の違いも、垣間見えたのではないかと思います。


PHPとJavaScriptでURLのクエリストリングを評価する

クエリストリングというのは、ほうぼうのWEBサービスでよく見かける、URLの後ろについた情報を持った文字列です。たとえば、youtubeで動画の検索をするとき、URLの後ろに ?search_query=検索文字列 として、URLにユーザ検索の内容をつけて遷移後のページに渡しています。
このクエリストリングは、search_queryのような普遍的な語でなくても、勝手な語を選んでつけることができます。そもそも、HTMLでフォームを作って送信方法にGETを選ぶと、input要素のユーザが設定したname属性がストリングになっていますね。またinput要素が複数の場合は、&で結ばれています。これもクエリストリングの特徴です。

さて、このクエリストリングをプログラム側でキー値と値の組で取得するにはどうすればよいでしょうか。

PHPでクエリストリング

PHPの場合、大抵の文字列操作は標準の関数として装備されています。本当に。自分で作る前にまず探してみると、大抵便利なのがあります。再発明した車輪はゴミの日にそっと出しましょう。

1.URL文字列からクエリストリングを取り出す場合
//このようなURLがあったとき
$url = "http://akisi.tabiyaku.net/index.php?query1=値1&query2=値2";
 
//クエリ部分を抽出する関数
$query = parse_url($url,PHP_URL_QUERY);
//$queryは"query1=値1&query2=値2"
 
2.現在のページのURLからクエリストリングを取得する場合
$query = urldecode($_SERVER["QUERY_STRING"]);
//urldecodeで、%E3みたいなコードになっているのをデコードする
 
3.取得したクエリストリングをキーと値の組に
parse_str($query,$arr);
 
//$arr["query1"]は値1
//$arr["query2"]は値2

3で$arrを指定しなければ、通常の変数($query1,$query2)にそれぞれの値が入ります。

JavaScriptでクエリストリング

JavaScriptの場合には、車輪の開発者になる余地が大いにあります。何故PHPのような標準でクエリストリングを扱う関数が無いのでしょう?簡単な話です。JavaScriptは未来の言語だからです。未来の車には、車輪など必要ありません!

1.URL文字列からクエリストリングを取り出す場合
 
//このようなURLがあったとき
var url = "http://akisi.tabiyaku.net/index.php?query1=値1&query2=値2";
 
//クエリ部分を抽出する(処理的には、?を探して以降の文字列をとる)
var query = url.slice(url.indexOf("?")+1);
//queryは"query1=値1&query2=値2"
 
2.現在のページのURLからクエリストリングを取得する場合
var query = decodeURI(location.search);
//decodeURIで、%E3みたいなコードになっているのをデコードする
//ただし、先頭に?を含むところがPHPと異なるので、?なしで取得する場合
var query = decodeURI(location.search).substring(1);
 
3.取得したクエリストリングをキーと値の組に
var arr = new Array();
var qarr = query.split("&");
for(i in qarr){
arr[qarr[i].substr(0,qarr[i].indexOf("="))] = qarr[i].substr(qarr[i].indexOf("=")+1);
}
//arr["query1"]は値1
//arr["query2"]は値2

こういった具合です。

実はJavaScript自体の関数ラインナップはPHPより劣るものの、PHPと同様の充実度を誇るのがjQueryです。確実に世界のどこぞの誰かが、あなたより先に車輪を開発してプラグインにしています。たとえばクエリストリングの評価ならば、jquery.toObject.jsこちらを使えばよろしいでしょう。こんな何某のWEB制作日記とか言う場末ブログのブックマークは、今すぐゴミ箱に放り込みましょう。