裏表(Phinloda のもう裏だか表だか分からないページ)

コンピュータ・プログラミング系の話がメインのそれなりにごちゃごちゃしたネタばかり出てくるサイトです。多分。
Eclipse + PHP + Xdebug が猛烈に重くなることがあるのだが

ステップ実行するときに異様に時間がかかる感じなので、ネットワーク系のボトルネックのような気もするのだが、PHPの方がメモリを食いまくるプログラムでコードもデカいので、そちらのせいかもしれない。 ただ、このような症状は最近で、2、3年前はもっとチープな環境だったのに、こんなに重いことはなかった。

全体的にpcの性能は上がっているので、その副作用とかあったりする?

JUGEMテーマ:コンピュータ

| PHP | 20:37 | comments(0) | trackbacks(0)
PDOエラーが出てしまって難儀したのだが

SQLのエラーでもあるのかと思ったが、そのようなエラー表示ではない。単に PDO のエラーだという。クエリがおかしいのかと思って、エラーの出るクエリのログを取って、それを直接 mysql client に突っ込んでみると、問題なく実行できる。わけがわからない。

結局、全角の空白が入っているのが原因だと分かったのだが、それって mysql client でもエラーにならなかったっけ?

JUGEMテーマ:日記・一般

| PHP | 21:28 | comments(0) | trackbacks(0)
PHP に str_replace という関数があるのだが

仕様書には文字列か配列を返す、とか書いてあると思う。

$str = str_replace('foo', 'bar', $orig);

こんなコードで、$orig が null だと何が返ってくるのかというと、null ではなくて空の文字列が返ってくるというあたりでハマってしまった。

JUGEMテーマ:日記・一般

| PHP | 20:30 | comments(0) | trackbacks(0)
Eclipse で PHP のコードを書いているのだが

何か結構恥ずかしい話のような気がしないでもないのだが、CakePHP でテストケースを書いているときに、getMock を使って動的にオブジェクトを作ることがあって、それ自体は問題ないと思うのだけど、Eclipse の上で cannot be rosolvied to a type というエラーが出る。確かに動的に作るオブジェクトだからコードを実行する前には存在しないクラスなのだが、このエラーを解決する方法が分からない。ググってみたが、それでもさっぱり分からない。

ググって見つからないというのは、探し方がダメなのかもしれないが、もしかしたら Cake を最新のバージョンに上げたら解決しているのかもしれない。使っているのは事情があってかなり古いバージョンなのである。

JUGEMテーマ:日記・一般

| PHP | 17:54 | comments(0) | trackbacks(0)
全く同じプログラムなのに挙動が異なるわけだが

コードが完全一致することは何度も確認したから間違いない。 プログラムはごく単純なもので、 とあるDBに接続して、カラムを取り出し、 生成しようとしているデータと同じレコードがあれば何もしない、 違うレコードがあれば insert する、単にその程度の処理である。

これで実行すると、あるサーバーでは10件しか一致しないものがないのに、他のサーバーで実行すると、一致しないものが数百件出てくる。もちろん、接続先のDBは同じだし、プログラムが完全一致しているのだから、接続のパラメータも一致している。

あとは違うものといえば、PHPのバージョン、OSのバージョン位で、PHPが怪しいのではないかという意見多数なのだが、こんな単純なプログラムがたかがPHPのバージョンごときで動作が変わるようなことが本当にあるのだろうか。

つまり、$a == $b という比較が、PHPのバージョンが違うと違った結果になる、みたいな。

JUGEMテーマ:コンピュータ
| PHP | 23:08 | comments(1) | trackbacks(0)
PHP の論理演算子の評価順序は決まっているのか?

C言語の演算子の殆どは、評価順序が決まっていない。決まっているのは、

「,」「&&」「||」「?:」

PHP は決まっているのだろうか、と思って web のマニュアルを見ると、 次のように書いてある。

演算子の優先順位や結合性は、あくまでも式のグループ分けだけを決めるものであり、評価順を決めるものではありません。 PHP では一般に、式をどの順番で評価するかは決めていませn。 そのため、特定の順序で式が評価されることを前提としたコードを書いてはいけません。 PHP のバージョンが変わったり前後のコードが変わったりしたときに、評価順が変わる可能性があるからです。

(PHP: 演算子の優先順位 - Manual)

英文だとこうである。

Operator precedence and associativity only determine how expressions are grouped, they do not specify an order of evaluation. PHP does not (in the general case) specify in which order an expression is evaluated and code that assumes a specific order of evaluation should be avoided, because the behavior can change between versions of PHP or depending on the surrounding code.

an order of evaluation は決まっていないというのである。 その後に例が出ているが、分かりにくい。 evaluation というのは、関数が呼ばれるところを想像すれば分かりやすい。

$i = (counter() + counter()) * counter();

counter() は、何度目に呼ばれたかというカウントを返す function だとする。 つまり、最初は1、2回目は2、3回目は3を返す。 どちらから呼ぶかというのが、order of evaluation である。 この例だと、左側から順に呼ばれたら、(1+2)*3=9 が $i に入る。 右側から呼ばれたら、(3+2)*1=6 になる。 order は決まっていないのだから、どちらになるか分からない。 括弧は、足し算を優先して計算する保証はするが、足し算の両側を先に呼び出すことまで保証しないのである。関数を全部呼び出してから計算するようになっているかもしれない。

そこで気になったのが、&& のような論理演算子である。 前述のように、C言語なら && は左から評価することが決まっているから、

if (0 && bar()) ..

この場合、0 を評価した時点で 0 && bar() の結果が 0 になることが確定する。 C言語の場合、このときに bar() は呼ばれない。 これを short-circuit evaluation (短絡評価)という…のだと長い間思っていた。 ひとまずそれを伏線にしておいて、 では、PHP だとどうなるか。

if (false && bar()) ..

false が先に評価されたら、その時点で、false && bar() の結果は確定する。 bar() の結果は関係ない。 しかし、先ほど紹介したように、PHP は演算子の評価順序を定めていない。 だから、もしかしたら bar() を先に呼び出して、true が返ってきてから false を評価しにいくかもしれない、と思ったわけだが、気になる記述がある。

// foo() will never get called as those operators are short-circuit

$a = (false && foo());
$b = (true  || foo());
$c = (false and foo());
$d = (true  or  foo());

(PHP: Logical Operators - Manual)

PHP でも、この場合、foo() は呼ばないというのだ。

&& が short-circuit だという仕様がどこに出ているのか確認できなかったのだが、 私は今まで、short-circuit evaluation というのは、最初の評価で結果が確定したら次の評価をしないで結果とする、というような評価方法だと思っていた。 評価順序が定義されていない言語の場合、どういう順序で評価するか分からないが、AND ならどちらかが false になった時点で残りは省略する、というような処理だと思ったのである。

この解釈だと、 PHP で && が short-circuit だと言われても、どちらを先に評価するか分からないのだから non-sense じゃないの、と思ったのである。 そこで、盲信するのは危険だという承知の上で、Wikipedia の Short-circuit evaluation の記述を見ると、こんな表現になっている。

the second argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression: when the first argument of the AND function evaluates to false, the overall value must be false; and when the first argument of the OR function evaluates to true, the overall value must be true

(Short-circuit evaluation - Wikipedia, the free encyclopedia)

the second というのは2番目、the firstというのは最初、というのは当然として、最初というのは何なのかという話。 つまり、この定義であったとして、右から左、right to left の順に evaluate するような programming language があったら、right が the first になるような可能性はあるのか? それとも、the first というのはプログラムを目で追うときに最初に出現するところの、必ず左側の argument を指すことになるのだろうか?

endian の話じゃないけど。右が最下位なのか、最上位なのか、みたいな。

もし the first というのが見た目の最初、つまり left side という意味なら、私の今までの理解とはちょっと違うことになるし、PHP のマニュアルの内容も筋は通るのかもしれない。

とはいっても、他の演算子はともかく、PHP も含めて、&& や || を右から評価する言語というのは今までに遭遇したことがないし、これからもないような気がしますね。何となくだが。 並列処理的には、こういう演算子の evaluation order が決まっていないのなら、同時にやりたくなったりするかもしれないけど。カウントを返す関数が同時に呼ばれるなんてのは、かなり頭痛い話だけど。

にしても、短絡評価って表現、何かいいよね。 うっかりさんというか、はやとちりっぽくて。

JUGEMテーマ:コンピュータ
| PHP | 11:19 | comments(37) | trackbacks(0)
Component の test case で class Component not found

CakePHP 2.4.10 で自作の Component の test case を書いたら、class Component not found とかいうエラーが出てしまってハマった。

結局、次のように書いていたのが原因だった。

APP::uses('Component', 'Controller/Component');

Component.php は Component ディレクトリではなく、Controller ディレクトリにある。だから、次のように書くのが正しい。

APP::uses('Component', 'Controller');

何となくハメられたようで釈然としないが…

JUGEMテーマ:コンピュータ
| PHP | 01:28 | comments(0) | trackbacks(0)
PHP で rtrim を使って文字列の最後のカンマを取り除く

ループ中に出現した string をカンマで区切って並べたいときに、 出てきた string の最後に「,」を付けてつなげていくと、 最後の string の後にもカンマが付くから「a,b,c,」のようになる。 この最後のカンマを付けないようにするのが面倒だ。

これはいちいち最後かどうか判定したり、 最初以外はカンマを付けるといった処理を最初にもってきたり、 そのような単純な考え方をするよりも、 とりあえず最後までカンマを付けておいて、最後にそれをカットするのが案外楽である。

このときに、PHP だと rtrim という関数が使える。 trim というのは他の言語にも出てくるが、PHP の rtrim は、対象となる文字を指定できるから便利で、つまり、カンマを指定すればカンマを最後から除去してくれるのだ。 こんな感じに書けばいい。

$str = rtrim($str, ",");

ところで、ググってみると、rtrim を使う他に、substr を使う流儀が多く見られた。 削除対象の文字が指定できるようになったのはバージョン 4.1.0 なので、それ以前の PHP では使えなかったのだ。 次のような処理になる。

$str = substr($str, 0, -1);

これでいいのだろうか。 もちろん、これは文字列の最後の1文字を取り除いた部分文字列を返すから問題ない…ように見える。 しかし、PHP のマニュアルにはこんなことが書いてある。

最低 1 文字以上を指定しなければなりません。

長さ0の string に対して substr を実行するのは仕様に反するのだ。 しかし、実際にループの中でカンマを付ける処理を作ると、

$str = "";
if (hoge()) {
    $str .= getString();
    $str .= ",";
}

このような処理の場合、1度も実行されずにループが終わってしまい、文字列の長さが0になってしまうこともなくはない。 では、この場合、substr の処理は一体どうなるのだろうか?

手元の環境で実行してみたが、特に何も起こらなかった。 つまり、substr("", 0, -1); は、何事もないかのごとく "" を返してくれた。 とはいっても、仕様的にはマズいので、事前に長さが1以上であることを調べたりすべきなのだが、だったら最初からそんな制限のない rtrim を使った方がお手軽な訳である。

JUGEMテーマ:コンピュータ
| PHP | 22:11 | comments(4) | trackbacks(0)
cakePHP + HighCharts plugin で Class not found

cakePHP に HighCharts plugin を使ってグラフを描こうとしたのだが、うまくいかない。 cakePHP の version は 2.4.10。 plugin は次の Github から get した。

https://github.com/destinydriven/cakephp-high-charts-plugin

バージョンが分からないが、2014-04-29 に controller が修正されているものを使った。 Github に書いてある通りにインストールすると、high_charts_demo が何の問題もなく期待通りに動く。

ところが、自作の app から同じように plugin を呼び出そうとすると、

Error: Class 'HighChartsAppController' not found

このようなエラーが出て表示できない。Github には次のように書いてある。

Implementing Highcharts to your app would simply include adding the Highcharts component to your controller. (See examples for more details)
public $components = array('HighCharts.HighCharts');

これが分からない。自作の Controller にはそのように書いてあるけど、その行を実行する以前に、extends の元になるクラスが見つからないのだから話にならなくて、挫折。

仕方ないので、Controller の先頭 ('<?php' の次の行)に、次のように書いて、plugin の path を指定したら、期待通りに動いた。当たり前だが。

App::uses('HighChartsAppController', 'Plugin/HighCharts/Controller');

こんな書き方が正しい方法だとは思えないのだが、どうも PHP は慣れてないので何が正しいのか判断できないのである。 何か設定漏れがあるような気はするのだが…

JUGEMテーマ:コンピュータ
| PHP | 01:37 | comments(2) | trackbacks(0)
 1/1PAGES 
Powered by "JUGEM"
▲このページの先頭へ
CALENDAR
S M T W T F S
      1
2345678
9101112131415
16171819202122
23242526272829
30      
<< September 2018 >>
NEW ENTRIES
CATEGORIES
ARCHIVES
NEW COMMENTS
NEW TRACKBACKS
LINKS
PROFILE