クラスの書き方とか、オブジェクト指向とは何だ、みたいな話はすぐに見つかるのですが、いかんせん使いどころが分からなくてずっと身に付かずにいました。
でもなんだか昨日書いたやつが自分の中では「クラスを書いて良かった」と思えた例だったので、備忘録として書いておきます。
なぜなら来月には忘れてしまうからです。
m(_ _)m
ずっと昔に買った入門書を片手に、ずっと昔に入れたphp5.3を使って勉強しているので、あれやこれの書き方が古い、そしてダサい、という点はどうぞご容赦ください。
1.とりあえず関数と変数を羅列した例
ニコニコ動画のURLから動画IDを読み取り、サムネイルなどの情報を取り出すコードです。
<?php
// 関数と変数を並べる
function get_id($url){
$id = strtr($url, array('http://nico.ms/'=>''));
return $id;
// この関数が有効なIDを取れているかどうかは、
// get_infoの実行結果で判定
}
function get_info($id){
$api = 'http://ext.nicovideo.jp/api/getthumbinfo/' . $id;
$xmlGet = file_get_contents($api);
return $xmlGet;
}
function get_contents($xml,$tag){
$tagLen = strlen($tag);
$tagL = '<' . $tag . '>'; // <hoge>
$tagR = '</' . $tag . '>'; // </hoge>
$offset = 0;
$posL = strpos($xml, $tagL, $offset);
if($posL === false){
$contents = '見つかりませんでした。';
}else{
// <hoge>の後方で</hoge>を探す
$offset = $posL + $tagLen +1;
$posR = strpos($xml, $tagR, $offset);
$contentsLen = $posR - $posL - $tagLen -2; // 2は < と >
$contentsPos = $posL + $tagLen +2; // 2は > とゼロ調整
$contents = substr($xml, $contentsPos, $contentsLen);
}
return $contents;
}
// つかいかた
$myurl = 'http://nico.ms/sm****';
$myid = get_id($myurl);
if($myxmlGet = get_info($myid) ){
$myxml = htmlspecialchars_decode($myxmlGet);
$info = '取得できた気がします。';
$nicoImg = get_contents($myxml, 'thumbnail_url');
$nicoRes = get_contents($myxml, 'last_res_body');
}else{
$info = '取得できませんでした。';
$nicoImg = '';
$nicoRes = '';
}
// 出力してみる
echo <<<HTML_
<html>
<head></head>
<body>
<p>結果: サムネイル情報を{$info}</p>
<p>動画ID: {$myid}</p>
<img src="{$nicoImg}" width="120" alt="画像がありません。">
<p>最近のコメント: {$nicoRes}</p>
</body>
</html>
HTML_;
get_id()でURLから動画IDを切り出し、get_info()でそれを元にAPIを叩いています。このAPIはサムネイル画像の場所や動画タイトル、再生回数、最新のコメントなどをXML形式で返してくれます。
(こんな感じです→ http://ext.nicovideo.jp/api/getthumbinfo/sm27979355 )
get_info()が成功したら、get_contents()で好きなタグの中身を取り出します。第2引数に'thumbnail_url'を指定すれば<thumbnail_url>と</thumbnail_url>に挟まれた部分を返す、という感じです。
ちょっと冗長なところ
get_id()をしてget_info()をしてその結果がfalseでなければ云々、のところを、1つの関数にまとめてしまうとか、if(get_info(get_id($url))) とかにできないかと思いました。
しかし、あとあと動画IDや取得したXMLを使い回したいので、やはり変数を作って取り置きしておく方が無駄がないです。
しかしこの変数名をいちいち考えるのも面倒なんすよね。
結局いつも意味不明な名前の変数を山ほど作っちゃうのです。どうせ2回くらいしか使わないのに。
2.クラスを書いてみた例
まったく同じ内容を、クラスを使って書き直してみました。
<?php
// クラスを作る
class NICONICO{
var $id;
var $xmlGet; // false または xmlの本文
var $xml;
// コンストラクタ
function niconico($url){
$this->id = strtr($url, array('http://nico.ms/'=>''));
$api = 'http://ext.nicovideo.jp/api/getthumbinfo/' . $this->id;
$this->xmlGet = file_get_contents($api);
$this->xml = htmlspecialchars_decode($this->xmlGet);
}
function get_contents($tag){
$tagLen = strlen($tag);
$tagL = '<' . $tag . '>'; // <hoge>
$tagR = '</' . $tag . '>'; // </hoge>
$offset = 0;
$posL = strpos($this->xml, $tagL, $offset);
if($posL === false){
$contents = '見つかりませんでした。';
}else{
// <hoge>の後方で</hoge>を探す
$offset = $posL + $tagLen + 1;
$posR = strpos($this->xml, $tagR, $offset);
$contentsLen = $posR - $posL - $tagLen -2; // -2は < と >
$contentsPos = $posL + $tagLen +2; // +2は > とゼロ調整
$contents = substr($this->xml, $contentsPos, $contentsLen);
}
return $contents;
}
}
// つかいかた
$myurl = 'http://nico.ms/sm****';
$mynico = new NICONICO($myurl);
if($mynico->xmlGet){
$info = '取得できた気がします。';
$nicoImg = $mynico->get_contents('thumbnail_url');
$nicoRes = $mynico->get_contents('last_res_body');
}else{
$info = '取得できませんでした。';
$nicoImg = '';
$nicoRes = '';
}
// 出力してみる
echo <<< HTML_
<html>
<head></head>
<body>
<p>結果: サムネイル情報を{$info}</p>
<p>動画ID: {$mynico->id}</p>
<img src="{$nicoImg}" width="120" alt="画像がありません。">
<p>最近のコメント: {$nicoRes}</p>
</body>
</html>
HTML_;
おわかりのように、クラスの書き方が絶望的に古いので、こちらをコピペすることはおすすめできません。
もし、クラスの書き方やニコニコ動画のAPIを知りたいかなと思っている初心者の方がいたら、ぜひ、他の賢人たちの記事を熟読していただき、クラス名をコンストラクタ名にしたり、アクセス修飾子を省略したりしないように、ご注意ください。
さて、クラスNICONICOは、コンストラクタがニコニコ動画のURLを引数に取ります。
そして、動画ID、XMLの取得結果、デコードしたXML、の3つをプロパティに保持します。
使うときは、new NICONICO でインスタンスを生成し、XMLの取得結果を確認し、get_contents()を使って好きなタグの中身を取り出します。
ちょっと嬉しいところ
動画IDの切り出しやXMLの取得の部分を、関数にしなくていい\(^o^)/
クラスを使わない方法では、この部分は「別なニコニコ動画のURL」が登場した時に再利用したいので、関数にしておく必要がありました。クラスを使えば、1つのニコニコ動画のURLに対して1つのインスタンスを生成すればいいので、ここの記述が簡潔になります。
関数の実行結果を使うか、使わないか、いつ使うか、事前に考えなくていい\(^o^)/
クラスを使わない方法では「後で動画IDを使いたいから」ということで、$myid という変数を作り、get_id()の結果を保持させていました。しかし、もし動画IDを後で使わないのなら、この1行は次の行とひとまとめにすることもできたし、そもそも関数を2つに分けなくて良かったです。
その上、重複を避けようとするならこの1行はここにしか記述できません。ずっと後の行で使うかもしれない変数 $myid を、ここにしか書けないので、コードがとっても見づらくなります。
クラスを使えば、使うか使わないか決めてない変数や、ずっと後で使うかも知れない変数について、悩むことが少なくなります。今回は、echo のところで突然 $mynico->id を呼び出してみました。ここで動画IDを使うか使わないかが、他の部分にあまり影響しないので、気楽に予定を変更できます。
3.まとめ ~どんなときにクラスを作ると嬉しいか~
ひとまとまりの処理を複数回繰り返すとき
今回の例なら、「ひとつのニコニコ動画のURL」に対して行なう処理が「ひとまとまりの処理」に当たります。ひとつのURLに対して一度しか行わない処理はコンストラクタに書き、ひとつのURLに対して複数回行なう処理はクラスのメソッドにしてみました。
##ある処理で生じた変数を、後で別な用途にも使いたいとき
場当たり的に変数を宣言していくと、その変数が元々はどんな事柄に属する情報だったのか、分からなくなります。変数の名前もどんどん長くて意味不明なものを作るしかなくなります。
クラスを使えば、これらの値は インスタンス名->プロパティ名 の形で呼び出すことができるので、常に身元のわかる肩書きを背負っているようなものですね。人間で言えば「会社名」や「名字」みたいなものかも知れないです。
というわけで、来月自分が忘れていたらこの記事を読み返すことにします。