最近Perlばっかりやってるじゃないかと、そうは思うのだけど、
だからといってWebプログラミングで使うのはPHPから変わらない。
まぁPHP自体、Perlと兄弟と言っていいほど似てるけど、
PHPはPerlのような過激な省略表現は通じないし、逆に厳格に事を運ぶことができる。
あと、文字列処理はPerlが、Webで役に立つ機能はPHPの方がそれぞれ優れています。
Perlのs/(foo+)/foo/g;、PHPの$_COOKIE[‘foo’]、どちらも変だけど扱いやすい。
PHPをコマンドラインで使えるからといって使う気にならないのは、コマンドラインでやりたいことは大方文字列処理だから。
逆はどうなんだという話だが、これはApacheにCGIの設定をするのがめんどくさいだけ。
実は、カウンター、クラスを使ったものに書き換えました。
べた書きだったものを、はがせる部分からクラスで表現することにした程度です。
その結果かなりスマートに見えます。
もともとそんなにごちゃごちゃしたプログラムでは無かったんだけどね。
実際どうしたかは省略するけど、まぁ見通しもいい。
PhpDocumentorを使って、Javadocのように、概要をHTMLに書き出してわかりやすくすることもできた。
C#のXMLDocumentationでもpublicなメソッド・プロパティには説明を付けるというルールでやってますからね。
このどうでもいいルールを守ることで非常に書きやすくなる。
ちなみにprivateの一部にも概要ぐらいは付けてることはある。けどあんまり意味ないしね。
さて、正直言うと、PHPのオブジェクト指向はJavaみたいだな。
どう考えても狙ってやってるとしか思えない。
ちなみにこのソースコードはコマンドラインでのテスト用のソース。まぁ考え方の確認のために作成してみた。
Windowsですが、なにげにPHPは入ってます。使い道はコマンドラインしかないですね。Apacheないし。
class person{
private $firstname,$familyname,$_age;
public function __construct($firstname,$familyname,$age){
$this->firstname=$firstname;
$this->familyname=$familyname;
$this->age=$age;
}
public function marge(person $other){
$other->familyname = $this->familyname;
}
public function __set($name,$value){
switch($name){
case 'age':
if($value<0) throw new Exception('Invalid age!');
$this->age = $value;
break;
default: throw new Exception('Field Not found!'); break;
}
}
public function __get($name){
switch($name){
case 'age': return $this->age; break;
case 'firstname': return $this->firstname; break;
case 'familyname': return $this->familyname; break;
default: throw new Exception('Field Not found!'); break;
}
}
public function __toString(){
return "$this->firstname $this->familyname($this->age)";
}
}
なんというか…PHPらしくもないソースコードですね。けどよく見ればPHPです。
アクセス修飾子は必須ではありません。省略すればpublicです。けど省略しませんよ。
PHPでは__(アンダースコア2つ)から始まるものは特別であるということだけど、
$_ageは特別ともいえないけど不気味な変数ということにしておいてください。
$firstname・$familynameは内部からは直接アクセスする変数、$_ageは内部からでもゲッター・セッター経由でアクセスするつもりの。
当然全部privateなので外部からアクセスはできません。
さて、それはともかく、コンストラクタは__constructです、昔はJava・C#のようにクラス名と同じ名前のメソッドだったんだけどね。
けど最近はこれらしいので、__constructを定義しました。
使うときは$p1=new person(‘Kenji’,’Kawaguchi’,20);のようにやります。こんなところもJava・C#と同じ。
Java・C#で言う、thisは、$thisです。もっともJava・C#では省略できるけど、PHPは省略不可能。
$foo->age=20; $foo->marge($bar);のようにこれも->でフィールド・メソッドを呼び出します。
非常にどうでもいいメソッドmargeを作ってみました。ここで引数リストを(person $other)のように型を付けているのはポイントです。
まぁ付けないのが普通だと思うけどね。けどこのように、このクラスのインスタンスという制限をかけることができる。
もちろんこの制限を付けなければ、偶然familynameというフィールド、または対応するセッターがあれば動くわけだから。
一長一短あるかと。
__setはセッターです。$p1->fooとして、public $foo;があればそれでいいんですが、アクセス出来ないときこれを呼び出します。
外部からは、どのフィールドでも、内部からでも$this->ageとしたら呼び出されますねぇ。
第一引数にフィールド名、第二引数にセットする値。
いろいろ考えたが、多分これがいいと思う。switchでフィールド名ごとに仕分けして、それぞれに書くと。
__getはゲッターで、これも同様の原理で動作し、第一引数にフィールド名。
ゲッターとセッターが分離されるのは気に食わんが、しかしこれで読み取り専用とか、値の制約とか簡単に実現できる。
throw new Exception(‘foo’);は例外を投げててるの。まぁ、これもJava・C#と一緒なのでなんというか…
__isset、__unsetは、アクセス出来ないフィールドに対応するisset、unsetの機能を、
__call、__callStaticは、どちらもアクセス出来ないメソッドを実行するやつ。ここまで来ると意味がわからん。
__toStringは等価な文字列を返す。これを定義すればecho “$p1\n”;のように扱えますよ。
まぁそんな具合でして、気合いをいれればかなり使い物になりますね。
なんせ、Javaに似ている、同時にC#に似ているというのはかなりありがたいことです。
ちなみに継承はclass runner extends person{ }のように行う。
抽象クラス・インターフェースなんかもあって、機能はやたら豊富。
まぁ好きなように使ってほしいということだろう。
PHPはオブジェクト指向を強要しないからね。けどそういう選択肢もあるよと。
まぁしかしながらかなり便利なので、これは今後活用していくよと、そういう風に思ったわけです。
最初に言った通り、ここで頭の整理のために、PhpDocumentorを使うことにしました。
これがどうもJavadocのパクリと言ってもいいような代物のようでして…
参考までにC#のXML Documentationについて、「DLLを身近に感じることができるクラスライブラリ」で取り上げています。
まぁ正直言うとこれとほとんど一緒。
さて、具体的な方法。
まずソースコードに特別なコメントを書き加える。
<?
/**
* オブジェクト指向を学習するインチキパッケージ
* @package foo
* @author Hidemaro ◆3rRY3LJ8tc
*/
$p1=new person('Kenji','Kawaguchi',20);
$p2=new person('Hanako','Tanaka',20);
$p1->marge($p2); echo "$p1\n$p2\n";
/**
* 人を表現するクラスです。
*/
class person{
private $firstname,$familyname,$_age;
/**
* コンストラクタです。氏名・年齢を登録します。
* @param string $firstname 名
* @param string $familyname 氏
* @param int $age 年齢
*/
public function __construct($firstname,$familyname,$age){ }
/**
* 等価な文字列を取得します。
* @return string 等価な文字列
*/
public function __toString(){ }
どうしてもかさばる…
/**~*/の間に書きます。**と2個あるのがポイントです。あと各行は*から始まる。
まずファイルの先頭にファイルについての概要を書く。
概要を1行程度で、そこから空行を開けて、長い説明を書くこともできる。
@authorとかは特別な意味をもつもの。@authorは作者、@packageはパッケージ名、適当につける。
クラスも同様。クラスの直前に書く。
フィールドについての記述法は省略。まぁフィールドを直接扱うことはないでということ。
メソッドは、これも直前に書く。まず概要を1行。必要なら空行を開けて詳しい説明を書く。
その後で引数・返り値の説明をする。
引数だが、@param string $familyname 氏のように書く、stringは型、$familynameは引数名、氏は説明。
ところでPHPの型だが、int,float,string,boolean,array(配列),resource(ファイルハンドルとか)が基本。
あとはobject、personなどのクラス名がある。しかしどの型でもいいときはある。そんなときはmixedと書くといいかな。
返り値は@return string 等価な文字列、のように型を書いて説明する。
これで基本的にOK、ただ難儀なのが__set,__get,__call,__callStaticで呼び出すことが前提の。
いろいろ議論されているようだが、まだ決まってないような気がするので、__set,__getの詳細部に書くことにした。
さて、書いたらどうするかというと、phpdocコマンドでHTMLに変換する。
pearでインストールします。pearはWindowsならばインストールしたディレクトリのgo-pear.batからインストール。
> pear install phpdocumentor
さて、これでインストール完了。
あとは非常に簡単です。
> phpdoc -t doc\ -d src\ -o HTML:Smarty:PHP
> phpdoc -t doc\ -f foo.php -o HTML:Smarty:PHP -q
-dでディレクトリ単位、-fでファイル単位で実行できる。
ディレクトリ内のPHPのソースコードと思われる拡張子のファイルを解釈する。
そして-t以下に結果のHTMLをはき出す。errors.htmlにエラーが書かれるので完了したら確認する。
-o HTML:Smarty:PHPはフォーマット。シンプルなフォーマットということらしいが、文字化けの問題が起きなくてラッキー。
詳しくは調べてください。他のでも文字コードをきちんと設定すればいいんです。
-qはあまりにうるさいから黙らせるために付けたオプション。
まぁこんな風に整理して入れておくと、後でわかりやすい。
それに、こういうルールでコメントを付けるとしておけば、作るときも楽だし、見たときもわかりやすい。
Perlにもperldocがあって、これも有名だけどね。まぁ調べてないだけ。
こういうクラスというのは誰がみてもわかるような工夫が欲しいと。
そういえばと思って、以前ダウンロードしたライブラリを見ると、docディレクトリがあるなぁ。
中身を見たらPHPDocumentorで作成されたHTMLだった。
ひたすら英語だし、専門用語が多くてわかりにくいけど、拾い読みできそうな気がする。
まぁこんな風に整理してあるのは大きそうです。