PHP、入れ子関数

PHPの関数は全てグローバル空間に配置されるため、どこからでも呼び出せる。
ただし、外側→内側の順で呼び出さなければならない。おそらく、外側の関数が呼び出されて初めて、内側の関数がグローバル空間に配置される、ということなのだろう。

function outer ($a)
{
function inner ($b)
{
echo "there $b";
}
echo "$a, hello ";
}
// outputs "well, hello there reader"
outer("well");
inner("reader");

サーバー不要!クロスドメインAjax実験

ランキングアニメーション・仕様書 – diary 六帖

の仕様を変更し、クロスドメインAjaxの威力を試すため、javascript内で完結できるようにした。前回書いたPHPのコードはとりあえず保留。

 

まず骨子を作る。

http://rokujo.esy.es/Responsive/ranking.html

23区ランキング

1(15) 千代田区 94点
2(16) 練馬区 78点
3(20) 渋谷区 76点
4(13) 江戸川区 73点
5(2) 板橋区 70点
6(18) 中央区 66点
7(1) 新宿区 65点
8(12) 品川区 59点
9(22) 港区 56点
10(17) 江東区 51点
2秒後に再読み込みします

10秒ごとに乱数で23区に点数を割り当ててランキング表示するだけ。これをクロスドメインAjaxを使用し、内容をYahooファイナンスの値上がり率ランキングから値をとってきたものに変え、jQueryで値をゲットして1分ごとに自動更新するようにしてみた。

http://rokujo.esy.es/Responsive/ranking_yf1.html

株式値上がり率ランキング

1(-) 9836 リーバイ・ストラウス ジャパン(株) +36.23%
2(-) 9687 (株)KSK +29.85%
3(-) 8073 (株)MAGねっとホールディングス +22.78%
4(-) 5962 浅香工業(株) +18.05%
5(-) 3664 (株)モブキャスト +17.4%
6(-) 3914 ジグソー(株) +16.83%
7(-) 7625 (株)グローバルダイニング +15.53%
8(-) 7217 (株)テイン +15.15%
9(-) 3318 (株)メガネスーパー +15%
10(-) 6267 ゼネラルパッカー(株) +14.56%
11(-) 3161 アゼアス(株) +14.53%
12(-) 3913 (株)sMedio +14.49%
13(-) 3912 (株)モバイルファクトリー +14.42%
14(-) 7638 (株)シーマ +10.71%
15(-) 6619 ダブル・スコープ(株) +10.57%
16(-) 6046 (株)リンクバル +9.96%
17(-) 9421 (株)ネプロジャパン +9.72%
18(-) 3825 (株)リミックスポイント +9.49%
19(-) 3355 クリヤマホールディングス(株) +8.39%
20(-) 4589 アキュセラ +7.84%
55秒後に再読み込みします

今日は日曜日なので値が更新されないが、一応機能を果たしているようだ。すごい。これでサーバー負荷は0だやった!動作は明日確認してみよう。あとは、アニメーション処理を作ることができれば完璧だが今日は時間が足りなかった。。

やっていることは、jquery.xdomainajax.jsを使って、次のように$.getで内容をゲットしているだけ。

function MakeRanking(prevRank, callback){

    var rank = new Ranking();
    rank.prefix = “+”
    rank.suffix = “%”;

    $.get(“http://info.finance.yahoo.co.jp/ranking/?kd=1&tm=d&mk=1“, function(data){
        var ranks = $(data.responseText).find(‘tr.rankingTabledata’);

        for(var i=0; i<ranks.length; i++){
            var elem = new RankingElement();
            var cols = $(ranks[i]).find(‘td’);
            elem.name = $(cols[1]).text() + ” ” + $(cols[3]).text();
            var tmp = $(cols[6]).find(‘span’);
            elem.value = Number($(tmp).text());
            rank.elements.push(elem);
        }
        rank.make(prevRank);

        callback(rank);
    });
}

リターンされたhtmlはそのままjQueryでパースすれば、内容のスクレイピングも簡単にしかも直感的にできた。

クロスドメインAjax – diary 六帖

ここでも書いたように、jquery.xdomainajax.jsを使えば自サーバーの負荷ははじめにhtml, jsファイルを読み込むときだけで、あとは何回再読み込み仕様が全くのゼロ。ただしアメリカYahoo!に負荷がかかる。


フリーダムPHPその3、多重ループを抜ける

PHPはwhileループやforループを何段階も抜ける記述方法がある。break 2; のように、breakのあとに数字を指定してやればよい。

<?php
$i = 0;
$j = 0;
while ($i < 10) {
while ($j < 10) {
if ($j == 5) {
break 2; // 2段階外側に抜ける
}
$j++;
}
$i++; //これは実行されない
}
echo "{$i}, {$j}"; // 0, 5
?>

ふつーの構造化プログラミング言語だったらbreakする前にフラグを立てて、1段階外でフラグを見てもう1段階抜けるって書き方をするけれど、PHPは自由だねぇー。

なんとcontinueも多重で抜けられる。

<?php
$i = 0;
$j = 0;
while ($i < 10) {
$i++;
while ($j < 10) {
if ($j == 5) {
continue 2; // 2つ上位のwhileまで戻る
}
$j++;
}
}
echo "{$i}, {$j}"; // 10, 5
?>

PHP、文字列インクリメント

PHPの可変変数に次ぐフリーダム仕様、文字列インクリメント。文字列aをインクリメントするとbになる。フハハ怖かろう。しかも繰り上がりもする。

$str = "a";
$str++;
echo $str; //b
$str = "z";
$str++;
echo $str; //aa
$str = "K9";
$str++;
echo $str; //L0
$str = "五";
$str++;
echo $str; //五

残念ながら日本語はインクリメントできないようだ。


PHP、演算子の優先順位

 PHPには多数の演算子がある。その優先順位は21段階にも及ぶ。

 

※上のものほど先に実行される

演算子の優先順位
結合時の評価 演算子 追加情報
結合しない clone new clone および new
left [ array()
right ** 代数演算子
right ++ ~ (int) (float) (string) (array) (object) (bool) @ および 加算子/減算子
結合しない instanceof
right ! 論理演算子
left * / % 代数演算子
left + . 代数演算子 そして 文字列演算子
left << >> ビット演算子
結合しない < <= > >= 比較演算子
結合しない == != === !== <> 比較演算子
left & ビット演算子 そして リファレンス
left ^ ビット演算子
left | ビット演算子
left && 論理演算子
left || 論理演算子
left ? : 三項演算子
right = += -= *= **= /= .= %= &= |= ^= <<= >>= => 代入演算子
left and 論理演算子
left xor 論理演算子
left or 論理演算子
left , さまざまな利用法

出典:PHP: 演算子の優先順位 – Manual

 

絶望的な気持ちになった。これを全部覚えるなんて死んでしまう。ところがProgramming PHPを読んでいたら、ありがたいアドバイスがあった。

One way many programmers deal with the complex precedence rules in programming languages is to reduce precedence down to two rules:
• Multiplication and division have higher precedence than addition and subtraction.
• Use parentheses for anything else. 

 

(適当訳)プログラミング言語の複雑な優先順位のルールに対して、多くのプログラマーは次の2つのルールに絞って対処する:

・掛け算割り算は足し算引き算より優先順位が高い

・あとはカッコに入れる

 なんだ自分がいつもやってることじゃないの!!あーよかった。


クロスドメインAjax

通常、ajax通信は同一ドメイン内でしか行えない。自サーバーのphpスクリプトなどを実行し動的に結果を取得するのに使われる。
しかし、ドメインを飛び越えてajaxを動作させる方法があるらしい。jquery.xdomainajax.js というスクリプトを使用する。

jquery.fn/cross-domain-ajax at master · padolsey-archive/jquery.fn · GitHub

公式サイトより抜粋

$('#container').load('http://google.com'); // SERIOUSLY!
$.ajax({
url: 'http://news.bbc.co.uk',
type: 'GET',
success: function(res) {
var headline = $(res.responseText).find('a.tsh').text();
alert(headline);
}
});
// Works with $.get too!

マジで!?URL入れるだけじゃん!?楽勝すぎる!しかも返ってくるのはjQueryオブジェクトなんだから、DOM操作もセレクタを使ったデータ収集も楽勝じゃん!

GitHubのコードを見ると、タネはYQLというYahoo.comのAPIを使っていることらしい。

       YQL = 'http' + (/^https/.test(protocol)?'s':'') + '://query.yahooapis.com/v1/public/yql?callback=?',
query = 'select * from html where url="{URL}" and xpath="*"';

つまり米Yahoo様の力を借りて、プロキシ的に他のサイトのデータをゲットしてしまうというわけなのか。リソースと金が余りまくってる会社の力を借りるのなら罪悪感はないね。採用決定!!
クロスドメインAjaxを使用する最大の利点は、回線や処理の負荷をクライアントに肩代わりしてもらう(悪い言い方をすれば、ユーザに押し付ける)ために、サーバーの負荷が大幅に軽減できるということ。レンタルサーバーを使っていても、転送量を気にすることなく他のサイトのhtmlを拾ってくることができる。これはとてもありがたい。


PHPの可変変数

Programming PHP で仕様の総確認をしていたら、「可変変数」なるものに出会った。なんじゃこりゃ?
簡単に言うと、「変数名を格納する変数」ということらしい。

$arg1 = "nannkadaru-";
$arg2 = "arg1";
echo ${$arg2}; // nannkadaru-

応用例は、例えば連番になっている変数をforループで処理する時など。

if($BUTTON1)
//略,10回繰り返し
if($BUTTON10)
↓
for ($i = 1; $i <= 10; $i++){
  if( ${"BUTTON".$i} ){

  }
}

わかりやすくなるが、可読性が下がるというトレードオフに悩まされそうな機能だ。もっとスマートな使い方があるような気がする。


ランキングアニメーション・仕様書

使用技術 jQuery+PHP+HTML5/CSS?

(PHP) 頻繁に更新されるランキングサイトにアクセスしスクレイピング、順位+タイトル+リンク+値を上から10番までゲットしてJSONで返す

(jQuery)1分ごとにajaxで↑のスクリプトを実行する。タイトルをキーにして、順位に変動があればDOMを書き換える。この際にアニメーションする。

次のサイトを使う。 値上がり率:株式ランキング – Yahoo!ファイナンス

納期 6/7

まずPHPまで完成。下のコードはjson_encodeではなくprint_rでテスト出力してあります。PHPもpython並に楽。

<?php
require_once 'simple_html_dom.php';
class RankInfo{
public $elements = array();
public $format;
}
class RankElement{
public $rank, $title, $body, $value;
}
$dom = file_get_html('http://info.finance.yahoo.co.jp/ranking/?kd=1&tm=d&mk=1');
$info = new RankInfo();
foreach($dom->find('tr.rankingTabledata') as $tr)
{
$atd = $tr->find('td');
$elem = new RankElement();
$elem->rank = $atd[0]->plaintext;
$elem->title = $atd[3]->plaintext;
$elem->value = $atd[6]->plaintext;
$elem->body = $atd[5]->plaintext.'('.trim($atd[7]->plaintext).')';
$elem->link = $atd[1]->find('a')[0]->href;
$info->elements[] = $elem;
if(count($info->elements) == 10) break;
}
print_r($info);
?>

実行例

RankInfo Object ( [elements] => Array ( [0] => RankElement Object ( [rank] => 1 [title] => (株)エムケイシステム [body] => 13,670(+2,830) [link] => http://stocks.finance.yahoo.co.jp/stocks/detail/?code=3910.t [value] => +26.11 % ) [1] => RankElement Object ( [rank] => 2 [title] => (株)ソフトフロント [body] => 325(+62) [link] => http://stocks.finance.yahoo.co.jp/stocks/detail/?code=2321.t [value] => +23.57 % ) [2] => RankElement Object ( [rank] => 3 [title] => (株)ナガホリ [body] => 328(+62) [link] => http://stocks.finance.yahoo.co.jp/stocks/detail/?code=8139.t [value] => +23.31 % ) [3] => RankElement Object ( [rank] => 4 [title] => 日本コンピュータ・ダイナミクス(株) [body] => 1,779(+300) [link] => http://stocks.finance.yahoo.co.jp/stocks/detail/?code=4783.t [value] => +20.28 % ) [4] => RankElement Object ( [rank] => 5 [title] => (株)MAGねっとホールディングス [body] => 121(+20) [link] => http://stocks.finance.yahoo.co.jp/stocks/detail/?code=8073.t [value] => +19.80 % ) [5] => RankElement Object ( [rank] => 6 [title] => シンデン・ハイテックス(株) [body] => 6,520(+1,000) [link] => http://stocks.finance.yahoo.co.jp/stocks/detail/?code=3131.t [value] => +18.12 % ) [6] => RankElement Object ( [rank] => 7 [title] => ムーンバット(株) [body] => 242(+35) [link] => http://stocks.finance.yahoo.co.jp/stocks/detail/?code=8115.t [value] => +16.91 % ) [7] => RankElement Object ( [rank] => 8 [title] => ITbook(株) [body] => 1,642(+215) [link] => http://stocks.finance.yahoo.co.jp/stocks/detail/?code=3742.t [value] => +15.07 % ) [8] => RankElement Object ( [rank] => 9 [title] => タケダ機械(株) [body] => 418(+49) [link] => http://stocks.finance.yahoo.co.jp/stocks/detail/?code=6150.t [value] => +13.28 % ) [9] => RankElement Object ( [rank] => 10 [title] => (株)マルマエ [body] => 1,263(+139) [link] => http://stocks.finance.yahoo.co.jp/stocks/detail/?code=6264.t [value] => +12.37 % ) ) [format] => )


PHPコードバラバラ殺人事件

PHPの技術が近いうちに必要になる事態になってしまったので、次の書籍を読んで知識総ざらい中。

Programming PHP: Kevin Tatroe, Peter MacIntyre, Rasmus Lerdorf: 9781449392772: Amazon.com: Books

読み始めたらいきなり打ちひしがれた。こんな記法ありなのね!

<?php while ($row = $result->fetch_assoc()) { ?>
<tr>
<td><?php echo stripslashes($row['title']); ?></td>
<td align="center"><?php echo $row['pub_year']; ?></td>
<td><?php echo $row['ISBN']; ?></td>
</tr>
<?php } ?>

HTMLタグ量産楽勝でした。HTML内のPHPの記述は意味のあるコードの塊を単位とするのだと思っていたのだけれど、まさか

<?php } ?>

のように中カッコまでいい加減な場所に書いていいだなんて!!JavaSctiptに劣らずフリーダムだったPHP。わたしゃわざわざ関数を書いて中で丁寧に文字列を繋げて返してたよ。