2013年3月30日土曜日

遅延静的束縛 その1

PHP5.3以降、遅延静的束縛という機能が追加されました。
これを使用すると、静的継承のコンテキストで呼び出し元のクラスを参照できるようになります。
具体的には以下のコードを御覧ください。

サンプルコード 実行結果
self:A
static:B
と、このようにselfとstaticで呼び出し先の関数が変わってしまいます。
この時、staticの方が遅延静的束縛と呼ばれるものです。
selfとstaticという書き方一つで意図しない結果になりうるため、
使いどころは非常に注意しないといけませんね。

2013年3月24日日曜日

__invoke

PHP5.3以降で使用可能な__invokeでは、
クラスオブジェクトが関数として呼ばれた場合の動作を決めることができます。

サンプルコード 実行結果
int(5)
果たしてクラスオブジェクトを関数として呼び出すことがあるのでしょうか?
一意な関数名も付けられませんし、分かりにくいだけのような気がします。

__toString

__toStringでクラスを文字列に変換された時の動作を決めることができます。

サンプルコード 実行結果
A
クラスを文字列として変換すること自体がまず無いでしょうし、
__CLASS__とでもしておくのが妥当なのではないでしょうか。

オブジェクトの反復処理

マニュアルを眺めていて知った小ネタです。
foreachなどを使用することによって
そのスコープからアクセス可能なメンバ変数全てを取得することができます。

サンプルコード 実行結果
var1 => value 1
var2 => value 2
var3 => value 3

MyClass::getProperty:
var1 => value 1
var2 => value 2
var3 => value 3
protected => protected var
private => private var
使うかな。使わなそうだなぁ…。

2013年3月23日土曜日

オーバーロード

PHPのオーバーロードは、動的にメンバ変数やメンバ関数を作成する機能を指します。

オーバーロードメソッドが起動するのは、
宣言されていないプロパティやメソッドを操作しようとしたときです。

また、現在のスコープからはアクセス不能なプロパティやメソッドを
操作しようとしたときにも起動します。

以下にその例を示します。

サンプルコード 実行結果
set a to 1
get a
1

Is a set?
bool(true)
Unset a
Is a set?
bool(false)

get _p

Notice: Undefined property via __get(): _p in 
C:\xampp\htdocs\test.php on line 51 in 
C:\xampp\htdocs\test.php on line 27
と、このように動的にメンバ変数を作成したり、取得・削除も行うことができました。
また、外部からアクセス不可能なメンバ変数にアクセスした時も
オーバーロードメソッドが実行されました。

いざ私の場合に置き換えてみますと有効な使い道は思いつかないのですが、
知っておいて損することはないので覚えておきたいです。

trait

PHP5.4からトレイトという機能が使用可能になりました。
トレイトはPHPのような単一継承言語の制約を減らすもので、
一つのクラスに複数のクラスを継承(厳密には違いますが)できるようにします。

それでは、トレイトでは何が継承できるか以下のコードでご紹介します。

サンプルコード 実行結果
Hello World!!
以上のように、トレイトではメンバ変数とメンバ関数が継承できることが分かりました。
この機能をうまく使えばコードの再利用がより簡単となり、
効率的なコーディングができるのではないでしょうか。

2013年3月20日水曜日

autoload

このようなファイルをあらかじめ作っておくと

MyClass1.php スクリプト中に__autoloadを定義しておくと自動的にincludeしてクラスを読みに行ってくれます。

サンプルコード この機能をどう思うかは人それぞれかと思いますが、
コード中にどのファイルがincludeされているか明記されなくなるので私は可読性が落ちると思っています。
ちなみにベンチマークです。

サンプルコード 実行結果
BenchMark 1     average:0.0052475452423096
BenchMark 2     average:0.0050734758377075
includeする分autoloadの方が遅いですね。

2013年3月18日月曜日

関数の定義

関数の定義方法について2種類ほどご紹介します。

サンプルコード 前者は多人数で実装を行う中規模以上のプロジェクトで私がよく使う方法です。
関数名の重複でエラーを起こしたくないですからね。
それでも、自分の書いた関数が定義されないのも困るので
重複しないような名前の関数を定義するのが一番大切なことだと思います。

後者は私は全く使ったことがありません。
あえて利点を挙げるとすれば…自分の任意のタイミングで関数を定義できることでしょうか。
スクリプト実行時に大量の関数が定義されるのを避けたくて
特定の関数が実行されると新たに関数が定義されるようにするとか…。
でもそんな事をするくらいなら別ファイルに関数を書いておいて任意のタイミングでincludeするほうが自然ですね。

というわけで関数の定義方法のご紹介でした。

2013年3月17日日曜日

関数の返り値を直接配列として扱うと…

以前の記事でPHP5.4から「関数やメソッドの返す結果を直接配列として扱える」ように
なったという事について例を示しました。
ですが、そのベンチマークを取り忘れていたので調査してみます。

サンプルコード 実行結果
BenchMark 1     average:0.012288689613342
BenchMark 2     average:0.0055228233337402
というわけで、普通の配列の倍以上の時間がかかることが分かりました。
これは、foreachのループごとに関数getArray()が実行されていることによるパフォーマンス低下と見なせます。
関数の返り値の利用が一度きりならまだしも、複数回参照するのでしたら一度変数に代入したほうが良さそうですね。

ループ内での要素の変更

配列のマニュアルを読んでいたら良さそうな例を見かけたので
メモ&ベンチマークです。

サンプルコード 実行結果
BenchMark 1     average:0.032666206359863
BenchMark 2     average:0.032941651344299
これからはパターン1で行こうと思います。

おかしな挙動?

最近になってPHPでどうしても理解できない挙動をする式を見つけました。
以下、そのサンプルコードと実行結果です。

サンプルコード 実行結果
1211
パターン1とパターン3、パターン2とパターン4が同じ結果になると思ったのですが、そうはなりませんでした。
パターン4の条件式ですが、普通に解釈すると右から解釈するので
$aに0が代入され、その$aをbooleanにキャストするのでFALSEになる筈なのですが…?
原因はわかりませんが、(bool)の型キャスト部分を消すと実行結果は1212と予想通りになります。
ともあれ、三項演算子と型キャストを同時に使うのは避けたほうがよさそうです。

配列について考える

今回は配列について考えます。
まずは配列についての基本的な知識から。

keyは整数 または 文字列です。 valueには任意の型を指定できます。

さらに、keyは指定される文字列によっては型キャストが発生します。
  • integer として妥当な形式の文字列は integer 型にキャストされます。
    つまり、キーに "8" を指定すると、実際には 8 として格納されるということです。
    一方 "08" はキャストされません。これは十進数として妥当な形式ではないからです。
  • floats もまた integer にキャストされます。
    つまり、 小数部分は切り捨てられるということです。
    たとえばキーに 8.7 を指定すると、実際には 8 として格納されます。
  • boolinteger にキャストされます。
    つまり、 キーに true を指定すると実際には 1 に格納され、
    同様にキーを false とすると実際には 0 となります。
  • Null は空文字列にキャストされます。
    つまり、キーに null を指定すると、実際には "" として格納されます。
  • arrayobject は、キーとして使えません。 キーとして使おうとすると Illegal offset type という警告が発生します。
サンプルコード 実行結果
array(1) {
  [1]=>
  string(1) "d"
}
上の例は、keyが全て1に型キャストされる例です。
keyが1にキャストされた結果、valueが上書かれて最終的にdになります。

では次に、PHP5.4以降で可能となった「関数やメソッドの返す結果を直接配列として扱える」という例をご紹介します。

サンプルコード 実行結果
array(5) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
  [4]=>
  int(5)
}
array(5) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
  [4]=>
  int(5)
}
と、このように関数の結果を一次変数に代入しなくても次の関数の引数に設定することができるようになりました。
今まで関数の結果を代入するだけだった変数が要らなくなったことは大きな進歩だと思います。

そしてPHP5.5以降では、配列リテラルをデリファレンスできるようになりました。
以下、マニュアルより抜粋したコードです。

サンプルコード 今回はここまでです。

文字数とバイト数のカウント

「PHPのマルチバイト文字は2バイトではありません。
マニュアルにも2バイトとは明記していません。」

(; ・`д・´) な、なんだってー!! (`・д´・ ;)

じゃあ何バイトなのかといいますとこれは文字コードに依存します。

例えば、「aaaあああ」は

mb_strlen:6
strlen(UTF-8):12
strlen(EUC-JP):9

となります。

文字数を取得するだけならばmb_strlenで解決するのですが、
バイト数で取得して欲しいという注文を受けることもあるかと思います。

そんな時に正直にstrlenを用いることはできません。
なぜなら、環境によってはstrlenがmb_strlenにオーバーロードされていることがあるためです。

ネットで調べた結果、この方法で安定してバイト数を出せるようです。 また、マルチバイト文字を2バイトとして数えたい場合は
文字列をSJIS-winに変換してから数える方法もあります。 機種依存文字の変換にいささか不安は残りますが、今回はこのあたりで閉めたいと思います。

ヒアドキュメントとNowdoc

ヒアドキュメントとNowdocのお話です。
ヒアドキュメントもNowdocも基本的にはほぼ同じですが、
内部に書かれた変数をパースするかどうかが違います。

ちなみに、Nowdocは<<<の後に続く識別子を'EOT'のように
シングルクォーテーションでくくることで書くことができます。

それでは、ヒアドキュメントとNowdocのサンプルコードです。

サンプルコード 実行結果
My name is "MyName".
My name is "$name".
ちなみに、ヒアドキュメントもNowdocも終了識別子の行で
改行せずにファイルを閉じようとすると「syntax error, unexpected end of file」というエラーが出ます。
私も今まで知らなかったのでこのエラーが出た時は少々驚いてしまいました。

いつも通りベンチマークも取っておきましょう。

サンプルコード 実行結果
BenchMark 1     average:0.27803311347961
BenchMark 2     average:0.27166895866394
ということで、予想通りNowdocの方が速いという結果になりました。

int型について考える

int型について考えます。
int型と言えば"整数型"ですが、整数の表現は様々なものがあります。
以下、その表現方法です。
  • 123      // 正の整数
  • -123     // 負の整数
  • 0b1011 // 2進数(先頭に"0b"をつける)
  • 0123    // 8進数(先頭に"0"をつける)
  • 0x123  // 16進数(先頭に"0x"をつける)
いかがでしょうか。一概に整数と言っても表現方法は様々ですね。

皆さんは普段は10進数しか使わないのではないでしょうか。
ここで一つ、2進数の有用な使い方をご紹介します。

以下、2つのサンプルコードをご覧ください。

サンプルコード
実行結果
FLAG1
FLAG3
FLAG5
サンプルコード 実行結果
FLAG1
FLAG3
FLAG5
と、このように5つの変数に分けて持っていたフラグが一つの変数にまとまりました。
結局フラグ比較する時に特定の2進数と比較しないといけないため複雑になっている気もしますが…。
このような扱い方もあります。という程度の紹介でした。
忘れずにベンチマークです。

サンプルコード 実行結果
BenchMark 1     average:0.0023561954498291
BenchMark 2     average:0.0024597406387329
可読性の問題もありますし素直に複数の変数にフラグを持ったほうがいいですね。

2013年3月16日土曜日

boolean型について考える

boolean型は真と偽の2つの値だけをとる最も単純な型です。
それゆえに、私を含めて多くの方はこの型を多用しているのではないでしょうか。
今回はそんなboolean型について考えます。

まずはbooleanで偽と扱われる値について
  • boolean の FALSE
  • integer の 0 (ゼロ)
  • float の 0.0 (ゼロ)
  • 空の文字列、 および文字列の "0"
  • 要素の数がゼロである 配列
  • メンバ変数の数がゼロである オブジェクト (PHP 4のみ)
  • 特別な値 NULL (値がセットされていない変数を含む)
  • 空のタグから作成された SimpleXML オブジェクト 
ここで注目すべき点はintegerおよび文字列の0です。
つまり、変数の値が0でないことが保証できればboolean型で空文字のチェックができます。

サンプルコード 実行結果
NULL : bool(false)
"" : bool(false)
"0" : bool(false)
"a" : bool(true)
0 : bool(false)
1 : bool(true)
+1 : bool(true)
-1 : bool(true)
0x0A : bool(true)
012 : bool(true)
0.1 : bool(true)
1e3 : bool(true)
1e-3 : bool(true)
array("") : bool(false)
array("a") : bool(true)
array(array("a")) : bool(true)
TRUE : bool(true)
FALSE : bool(false)
object : bool(true)
fopen : bool(true)
では、肝心のベンチマークを取ってみましょう。

サンプルコード 実行結果
BenchMark 1     average:0.0022930383682251
BenchMark 2     average:0.0024604082107544
そして、最後に注意点をひとつ。未定義の変数を判別しようとしますと…。

サンプルコード 実行結果
Notice: Undefined variable: x in C:\xampp\htdocs\test.php on line 2
と、Noticeが出てしまいます。
この場合は素直にissetやemptyを使ったほうが良いでしょう。

xamppでcURLを使う その2

xamppでcURLを使う その2です。
今回は複数のサイトに並列アクセスをかけてみましょう。

サンプルコード 今回も実行結果は省略いたしますが、取得先のページのソースコードが表示できれば成功です。

xamppでcURLを使う その1

準備

C:\xampp\php\php.ini

にて

extension=php_curl.dll

の文頭から”;”が外れていることを確認します。

もしくは phpinfo()のページから

 「cURL support」がenabledになっていることを確認します。

サンプルコード 実行結果は省略いたしますが、取得先のページのソースコードが表示できれば成功です。

文字列検索 その3

文字検索におきまして検索文字もしくは検索対象が複数ある場合はstrposを使っても良いのでしょうか?
悩んでいましたところ、preg_grepという良さそうな関数を見つけたので
ベンチマークをとって試してみることにしました。

サンプルコード 実行結果
BenchMark 1     average:0.065507936477661
BenchMark 2     average:0.061827921867371
以上のような結果となりました。
コードもスッキリしますし、検索対象が複数ある場合はpreg_grepを利用した方が良さそうです。

文字列検索 その2

文字列検索その2。
今回は大文字小文字を区別しない場合です。

サンプルコード 実行結果
BenchMark 1     average:0.064927673339844
BenchMark 2     average:0.062755298614502
やはりstriposの方が速いようです。
素直にstriposを使うほうがベターですね。

文字列検索 その1

前回の文字置換の流れに続きまして、今度は文字検索についてベンチマークを取ってみました。

サンプルコード 実行結果
BenchMark 1     average:0.0086915016174316
BenchMark 2     average:0.070313191413879
BenchMark 3     average:0.009862232208252
BenchMark 4     average:0.0227707862854
こちらも綺麗に結果が出ましたね。
strstrのマニュアルにも書いてありますが、単純に文字列の有無を知りたい場合は
より高速でメモリ消費も少ないstrposを使うのが良いでしょう。

文字列置換の注意点

PHPで複数の単語を一気に置換することがあると思います。
そういった場合における注意点です。

サンプルコード 実行結果
strtr
cba abc
cba abc

str_replace
abc abc
cba cba

preg_replace
abc abc
cba cba
と、上記のようにstrtrでは配列の順序に関わらず一定の結果を返すのに対し、
str_replaceとpreg_replaceでは配列の順番によって結果が異なります。

ちなみにベンチマークです。

サンプルコード 実行結果
BenchMark 1
BenchMark 1     average:0.016364622116089
BenchMark 2     average:0.019233679771423
BenchMark 3     average:0.045470118522644
きれいに結果に差が出ましたね。
単純な置換ではstrtrを使用するのが安全かつ高速のようです。

最後の一文字

先日、PHPで文字列から最初の一文字を取る方法について記事を書きました。
今回は最後の一文字を取る方法について調査してみました。

方法1
$str = 'abcde';
substr($str, -1);
方法2
$str = 'abcde';
$str{strlen($str)-1};
サンプルコード 実行結果
BenchMark 1     average:0.0076918125152588
BenchMark 2     average:0.0067881345748901
あんまり差がつきませんでしたね。
速度を取るなら後者、文字数を取るなら前者でしょうか。

issetの落とし穴

issetにおいて気をつけなければいけないことです。

サンプルコード 実行結果
bool(true)
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
と、文字列のオフセットに数値以外の値を渡した場合、結果はFALSEになります。

2013年3月15日金曜日

ファイル一覧の取得

PHPでファイル一覧を取得する関数として、scandirglobという2つの関数があります。
今回はその2つの関数について調べてみました。

サンプルコード 実行結果
scandir
array(11) {
  [0]=>
  string(1) "."
  [1]=>
  string(2) ".."
  [2]=>
  string(9) ".htaccess"
  [3]=>
  string(13) "BenchMark.php"
  [4]=>
  string(8) "Util.php"
  [5]=>
  string(14) "Validation.php"
  [6]=>
  string(3) "doc"
  [7]=>
  string(3) "git"
  [8]=>
  string(9) "index.php"
  [9]=>
  string(8) "test.php"
  [10]=>
  string(9) "test2.php"
}
glob
array(8) {
  [0]=>
  string(13) "BenchMark.php"
  [1]=>
  string(8) "Util.php"
  [2]=>
  string(14) "Validation.php"
  [3]=>
  string(3) "doc"
  [4]=>
  string(3) "git"
  [5]=>
  string(9) "index.php"
  [6]=>
  string(8) "test.php"
  [7]=>
  string(9) "test2.php"
}
上記の結果のように、scandirではカレントディレクトリを表す"."と、親ディレクトリを表す".."、
さらには"."から始まる隠しファイルも取得できるようです。
逆に言えば、globではこれらのファイル名は取得できないということですね。

intからfloatへ

PHPの型は動的なので意図せずに型が変わってしまう場合があります。
今回はその一例をメモいたします。

サンプルコード 実行結果
int(2147483647)
float(2147483648)
int(-2147483648)
と、このような現象が起こる場合もあります。
以上、備忘録でした。

配列の添字の変更

先日ふと疑問に思ったことです。
配列の添字を変えたい場合はどうするのがスマートなのでしょうか?

とりあえず自分で考えた実装 なんのひねりもない上に2行で処理しているのがとても気持ち悪いですね。
特定の場合に限りarray_popなどを使用する書き方もありますが汎用的ではありませんし…。

以上、気になった出来事でした。

変数のswap

小ネタです。
PHPで変数の値を入れ替えたいときの定石ですね。

サンプルコード 実行結果
int(1)
int(2)
int(2)
int(1)
ただ、未だに変数の値を入れ替えたい状況というのに出会ったことがありませんw

定数を動的に呼び出す

constantを使うことで定数を動的に呼び出すことができます。

サンプルコード 実行結果
aaaaa
使う機会は無くはないといったところでしょうか。

コード短縮手法4

コードの短縮手法として有名なものに三項演算子があります。
では、三項演算子のパフォーマンスについて調べてみましょう。

サンプルコード 実行結果
BenchMark 1     average:0.01190493106842
BenchMark 2     average:0.012681221961975
三項演算子は遅いという印象はありましたが
この結果を見る限りではそこまで遅くはないようですね。

elseとcontinue

if文を書くときにelseとcontinueのどちらを使うのがベターなのでしょうか。
ベンチマークを取って調べてみましょう。

サンプルコード 実行結果
BenchMark 1     average:0.51706559658051
BenchMark 2     average:0.51087384223938
この結果を見るには大差無さそうですね。

2013年3月14日木曜日

配列の結合について

配列の結合にはarray_mergeを使う方法と+演算子を使う方法があると思いますが、違いについて確認してみました。

サンプルコード
実行結果
Array
(
    [0] => a0
    [1] => a1
    [2] => a2
    [a] => ba
    [b] => bb
    [c] => bc
    [3] => b0
    [4] => b1
    [5] => b2
)
Array
(
    [0] => a0
    [1] => a1
    [2] => a2
    [a] => aa
    [b] => ab
    [c] => ac
)
ということで、表にまとめるとこのような感じになります。
配列の結合と重複した添字の関係
数値文字列
array_merge後の配列は後ろに追加後の配列の値で上書き
前の配列の値で上書き前の配列の値で上書き

ちなみに、お決まりのベンチマークです

サンプルコード 実行結果
BenchMark 1     average:0.029446578025818
BenchMark 2     average:0.011990690231323
やっぱりarray_mergeを使わない方が速いですね。
ですがこの二種類は使い所が違うので、違いをしっかり把握しておくことが重要だと思います。

PHPの閉じタグ

Zendのコーディングルールにも記載されている基本的な話ですが。

ライブラリファイルのような何も出力をしないPHPファイルにおきまして、PHPの閉じタグ ?> は使ってはいけません。

PHPでは閉じタグの直後の改行は消してくれるのですが、閉じタグ以降に改行が2行以上入った場合は2行目以降の改行は消してくれません。

サンプルコード
config.php index.php 実行結果
Warning: Cannot modify header information - headers already sent by
と、このようにWarningが発生し、リダイレクトしてくれません。

以上、まめちしきでした。

PHPでの出力 その5

前回までの内容を踏まえて、今回はもう少し実用的な例でテストしてみましょう。

サンプルコード 実行結果
BenchMark 1     average:1.4885204076767
BenchMark 2     average:1.8529042959213
BenchMark 3     average:0.45898940563202
BenchMark 4     average:0.46037158966064
この結果より何度もphpの開閉タグを開いたりechoで直接出力するよりも
一旦変数に格納してから出力するのが最善かと思われますね。
では、次のような場合はどうでしょうか。

サンプルコード 実行結果
BenchMark 1     average:0.51002349853516
BenchMark 2     average:0.5392422914505
これですとパターン1の方が速いですね。
少し複雑ですが、とりあえず覚えていて損は無いかと思います。

PHPでの出力 その4

PHPでの出力 その4です。
今回は複数行の出力について調べてみます。

変数なしの場合

サンプルコード 実行結果
BenchMark 1     average:0.25352725982666
BenchMark 2     average:0.099978256225586
BenchMark 3     average:0.10105469226837
BenchMark 4     average:0.10030741691589
BenchMark 5     average:0.099922490119934
BenchMark 6     average:0.098655319213867
変数ありの場合

サンプルコード 実行結果
BenchMark 1     average:0.25069181919098
BenchMark 2     average:0.10060927867889
BenchMark 3     average:0.10188813209534
BenchMark 4     average:0.097803926467896
BenchMark 5     average:0.10043952465057
HTMLベタ書きが最速なのは当然として、それ以外はあまり差がつきませんでしたね。
遅いと言われているヒアドキュメントもそこまで遅いというわけでもありませんでしたし。
ちなみに私はパターン4の書き方が好みです。

PHPでの出力 その3

PHPでの出力 その3です。
今回はピリオド・コンマそれぞれで文字を連結した場合を確認してみましょう。

サンプルコード 実行結果
BenchMark 1     average:0.10389432907104
BenchMark 2     average:0.50043830871582
ピリオドよりもコンマでの連結のほうが速くなると思ったのですが…。
この結果は少し不可解です。
実行環境の問題ですかね?

PHPでの出力 その2

PHPでの出力 その2です。
今回は改行について調べます。

サンプルコード 実行結果
BenchMark 1     average:0.020783019065857
BenchMark 2     average:0.034758615493774
速度では圧倒的に「\n」の方が速いですが、
汎用性を考えて「PHP_EOL」を使うのもいいかもしれませんね。

2013年3月13日水曜日

変数と配列

今日も今日とて趣味のベンチマークです。
小さな積み重ねがいつか実ると信じています。

今回は変数と配列の扱いについてです。

サンプルコード 実行結果
BenchMark 1     average:0.0046348333358765
BenchMark 2     average:0.01211142539978
BenchMark 3     average:0.012383699417114
変数と比べて配列は3倍くらい遅いですね。
配列の利点の一つとして同じ属性の変数をまとめて分り易いコードを書ける点だと思います。

また、変数と配列の出力についても調査してみました。

サンプルコード 実行結果
BenchMark 1     average:0.2620055437088
BenchMark 2     average:0.26266303062439
BenchMark 3     average:0.26184134483337
こんな感じでした。
一概に変数と配列のどちらが優れているとは言えませんが、
使いどころについては考えたほうが良さそうです。

厳密なチェックを

PHPには「==」と「===」という2種類のチェック方法があります。
前者は単純に文字列の比較だけ、
後者は厳密に型チェックまで行うというのは周知のことかと思います。
ではベンチマークを取ってみましょう。

サンプルコード 実行結果
BenchMark 1     average:0.0028216361999512
BenchMark 2     average:0.0024353981018066
と、後者のほうが速いです。
厳密にチェックしている方が実行速度が速いというのも不思議な感じがしますね。
不慮の事故を防ぐためにも、「===」でのチェックを積極的に使っていきましょう。

ローカル変数とメンバ変数

メンバ変数は一般に遅いと言われていますがどれくらい遅いのでしょうか?
実際に調査してみました。

サンプルコード 実行結果
BenchMark 1 average:0.11058385372162
BenchMark 2 average:0.11761968135834
BenchMark 3 average:0.11095626354218
ローカル変数よりメンバ変数が遅いのはともかくとして、比較するとstaticの方が速いですね。
当然といえば当然の結果ですが。

気になったのであと数パターン試してみました。

サンプルコード 実行結果
BenchMark 1     average:0.58168365955353
BenchMark 2     average:0.56918079853058
サンプルコード 実行結果
BenchMark 1     average:0.58172357082367
BenchMark 2     average:0.58285653591156
今回はここまでです。

タイプヒンティング

今更ながらPHPのマニュアルには有益な情報が沢山載っていることに気づきました。
関数を調べるときにだけマニュアルを見るくらいでしたが、それでは勿体無いですね。

遅まきながら知った情報として、タイプヒンティングがあります。

サンプルコードはマニュアルに載っているので省略し増ますが、要するに関数の引数の型を指定できるという内容です。
残念ながらintstring といったスカラー型には使えませんが、有効に使えば関数内での引数チェックの手間が省略できそうですね。

コード短縮手法3

小ネタです。
if文の書き方でひとつ。

サンプルコード 実行結果
BenchMark 1     average:0.014285373687744
BenchMark 2     average:0.013172221183777
とまあ、わずかばかり後者のほうが速かったりもします。

コード短縮手法2

コード短縮手法、第二回目です。
今回はif文の短縮手法をご紹介します。

サンプルコード 実行結果
FLAG1
FLAG1
FLAG2
FLAG2
いかがでしょうか。
条件の真偽さえ間違えなければ便利な書き方といえるのではないでしょうか。
ただし、この書き方はelse節が無いことが前提条件です。
else節がある場合は三項演算子を使うのがコードの短縮になるかと思います。

ではベンチマークも取ってみましょう。

サンプルコード 実行結果
BenchMark 1 average:0.010251259803772
BenchMark 2 average:0.0099292039871216
サンプルコード 実行結果
BenchMark 1     average:0.10526418685913
BenchMark 2     average:0.10484325885773
このような結果になりました。
限定的な場合だけ通じる書き方ですが、一度試してみてはいかがでしょうか。

コード短縮手法1

普段簡単なコードを書く時はできるだけ手短に書きたいものです。
今回はfor文を簡単に書く方法をご紹介します。

サンプルコード 実行結果
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
いかがでしょうか。
ポイントは初期化の時に1引く点、後置インクリメントが前置インクリメントになる点と
echoではなくprintを使う点です。
ここでprintではなくechoを書きますとエラーが起きます。

ベンチマークも取ってみましょう。

サンプルコード 実行結果
BenchMark 1 average:0.10385200977325
BenchMark 2 average:0.10636031627655
自分だけが見るコードでしたら少々トリッキーなこんな書き方もアリではないでしょうか。

rangeを使おう

簡単なテストコードを書く際に配列を生成する場合があるかと思いますが、
そのような時はrange関数を使うと楽です。

サンプルコード 実行結果
array(5) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
}
array(5) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
}
速度調査もしてみます

サンプルコード 実行結果
BenchMark 1     average:1.6927280902863
BenchMark 2     average:1.0643670082092
速度的にも後者のほうが良いですね。

一文字だけ欲しい

PHPでスクリプトを書いていて変数の最初の一文字だけ欲しい事ってありませんか?
そのような場合にはどうすればよいでしょうか?

このような書き方をしている人も居るかと思います。
ですが、もう少しベターな案を見つけましたのでメモ。
こちらの方がスマートです。
ちなみに、お決まりのベンチマーク。

サンプルコード 実行結果
BenchMark 1     average:0.084321331977844
BenchMark 2     average:0.034408354759216
速度も問題ありませんね。

2013年3月12日火曜日

Validation その3

今回は数値についてです。これが厄介です。
普通、数値と言いますと自然数を想定してコーディングする方が多いかと思います。
ですが、プログラム上で表現できる数値には様々な種類があります。



  • 符号の有無(+-)
  • 基数の違い(2進数、8進数、10進数、16進数)
  • int型の範囲(32ビット符号付ですと-2147483648~2147483647)を超える数値
  • 浮動小数点
  • 指数表現

これらの値について、使用しても良いかどうかを考慮しつつコーディングをしていかなければなりません。
今回は数値の中でも最も頻繁に使われる形式、Integerについて考えていきましょう。

チェックの手順

1. 引数がint型かどうかを調べる
int型ならreturn

2. int型でなければ次の可能性が上げられる
2.1 float型
2.2 string型の数値文字列
2.3 数値とは全く関係のない値

3. int型にキャストする際に注意すべき点
3.1 int型を超えた値でないか
超えていたらNULLを返す
超えていなければint型にキャストした値を返す

4. 数値とは全く関係ない値の場合
NULLを返す

サンプルコード 実行結果
NULL : NULL
"" : NULL
"a" : NULL
0 : int(0)
1 : int(1)
+1 : int(1)
-1 : int(-1)
0x0A : int(10)
012 : int(10)
0.1 : int(0)
1e3 : int(1000)
1e-3 : int(0)
array("") : NULL
array("a") : NULL
array(array("a")) : NULL
TRUE : NULL
FALSE : NULL
object : NULL
fopen : NULL
成功です。以降、数値のチェックをする際はこの関数を使って入力チェックを行っていきます。

Validation その2

今回は配列の判定です。これも簡単ですね。

取得したい値と弾きたい値の仕様について考えましょう。

取得したい値

  • array
弾きたい値
  • NULL
  • integer
  • float
  • string
  • boolean
  • object
  • resouce

サンプルコード 実行結果
NULL : array(0) {
}
"" : array(0) {
}
"a" : array(0) {
}
0 : array(0) {
}
1 : array(0) {
}
+1 : array(0) {
}
-1 : array(0) {
}
0x0A : array(0) {
}
012 : array(0) {
}
0.1 : array(0) {
}
1e3 : array(0) {
}
1e-3 : array(0) {
}
array("") : array(0) {
}
array("a") : array(1) {
  [0]=>
  string(1) "a"
}
array(array("a")) : array(1) {
  [0]=>
  array(1) {
    [0]=>
    string(1) "a"
  }
}
TRUE : array(0) {
}
FALSE : array(0) {
}
object : array(0) {
}
fopen : array(0) {
}
ちなみに、実際に使用するときは以下のように判別して使用します。

Validation その1

スクリプトを書いていて気を使うところは変数のバリデーションです。
今回はその中で、scalar値かどうかの判別について考えたいと思います。

まず、取得したい値と弾きたい値の仕様について考えます。
取得したい値
  • integer
  • float
  • string
  • boolean

弾きたい値
  • NULL
  • array
  • object
  • resouce

というわけで、実装した関数はこうなりました。

サンプルコード

実行結果
NULL : string(0) ""
"" : string(0) ""
"a" : string(1) "a"
0 : int(0)
1 : int(1)
+1 : int(1)
-1 : int(-1)
0x0A : int(10)
012 : int(10)
0.1 : float(0.1)
1e3 : float(1000)
1e-3 : float(0.001)
array("") : string(0) ""
array("a") : string(0) ""
array(array("a")) : string(0) ""
TRUE : bool(true)
FALSE : bool(false)
object : string(0) ""
fopen : string(0) ""

上記の通り、特に問題なさそうです。
スカラー値を取得したいときはこの関数を使用していきたいと思います。

テストパターン

自分の書いたコードのテストをする度にパターンマトリックスを作成するのは非効率的なので、
あらかじめパターンを作っておくことにしました。

TestClass

使用方法 実行結果
array(19) {
  ["NULL"]=>
  NULL
  [""""]=>
  string(0) ""
  [""a""]=>
  string(1) "a"
  [0]=>
  int(0)
  [1]=>
  int(1)
  ["+1"]=>
  int(1)
  [-1]=>
  int(-1)
  ["0x0A"]=>
  int(10)
  ["012"]=>
  int(10)
  ["0.1"]=>
  float(0.1)
  ["1e3"]=>
  float(1000)
  ["1e-3"]=>
  float(0.001)
  ["array("")"]=>
  array(0) {
  }
  ["array("a")"]=>
  array(1) {
    [0]=>
    string(1) "a"
  }
  ["array(array("a"))"]=>
  array(1) {
    [0]=>
    array(1) {
      [0]=>
      string(1) "a"
    }
  }
  ["TRUE"]=>
  bool(true)
  ["FALSE"]=>
  bool(false)
  ["object"]=>
  object(stdClass)#2 (0) {
  }
  ["fopen"]=>
  resource(9) of type (stream)
}

これでテスト時のパターン作成を行う必要がなくなりました。
何か改善点を思いつき次第もう少し拡張してテストの手間を省けるようにしたいですね。

Dumper

var_dumpはよく使う関数ですが、毎回打つのが面倒なのでエイリアスを作ることにしました。
これで少しは楽できますね。

デバック時に便利な関数

ついつい忘れがちですが、PHPにはこんな便利な関数があります

全ての定義済の変数を配列で返す
get_defined_vars

すべての定数の名前とその値を連想配列として返す
get_defined_constants

定義済みの全ての関数を配列で返す
get_defined_functions

定義済みの変数を意図せずに上書きしてしまったり、関数名の衝突を防ぐためにも積極的に使っていきましょう。

PHPでの出力 その1

PHPで出力なんて特に気にせず行っている方も多いでしょう。
しかし私は神経質なせいか出力方法によるパフォーマンスが気になってしまいます。

1回の記事では全てを網羅できないと思いますので複数回に分けて書こうかと思います。
echoとprintの測定は前回の記事で行い、echoの方が速いという結果が出ましたので以降のサンプルコードはechoで統一したいと思います。

今回はシングルクォーテーションとダブルクォーテーションの比較です。

変数なしの場合

サンプルコード 実行結果
BenchMark 1     average:1.0819767475128
BenchMark 2     average:1.1022774219513
変数ありの場合

サンプルコード 実行結果
BenchMark 1     average:1.1036427974701
BenchMark 2     average:1.1097546815872
ダブルクォーテーションでは意図しない変数展開が起きてしまう場合も皆無ではありませんので
私は常にシングルクォーテーションを使うようにしています。

BenchMark

よくPHPのコーディングに悩んだ際にベンチマークを取ります。
というわけでベンチマークに利用するスクリプトを書いてみました。

BenchMark.php

例えば、echoとprintのどちらが速いのかを
調査したいときには以下のようにして使用します。

サンプルコード 実行結果
BenchMark 1 average:0.87322912216187
BenchMark 2 average:0.88909468650818
と、このようにコードの実行速度の比較ができます。

PHPDocumentorを使おう

エンジニアならば自分の作った関数やクラスの一覧を見てニヤニヤしたい時があるかと思いますw
というのは半分冗談ですが、PHPDocumentorを開発環境に導入してみました。

導入にはpearを利用しています。

pear channel-discover pear.phpdoc.org
pear install phpdoc/phpDocumentor-alpha 

インストールが終わりましたら早速実行してみましょう。

phpdoc run -d C:\xampp\htdocs\git -t C:\xampp\htdocs\doc

これでドキュメントを生成してくれるのですが毎回打つのが面倒なので、batファイルにしておくことをオススメします。

ちなみに、オプションの解説をしますと

-d ドキュメントを生成したいファイルのあるディレクトリ
-t ドキュメントの出力先

以上です。

詳しいことは本家のドキュメントをご覧ください。

PHPDocumentor

finalize

コマンドプロンプトにおきましてinitializeはレジストリから設定できますが、
finalizeは使えるのだろうかとふと疑問に思いました。

結論から言えば、finalizeはレジストリでは設定できないようでした。

特に何かしたいわけでもありませんが、以下の方法でfinalizeを設定しました。

1. fin.batを作成
2. pathの通っているディレクトリにfin.batを設置
3. init.batに以下の記述を追加

doskey exit=fin $t exit

使い道はこれから考えますw

コマンドプロンプト

さて、いよいよ開発を始めたわけですが、気になる点が出てきました。

私が開発を始める手順なのですが、以下のような手順を踏んでいます。

  1. Ctrl+R(ファイル名を指定して実行)
  2. 「cmd」と打ち込んで実行
  3. cdで開発ディレクトリまで移動
このうち、3の手順を省略できないかなと思い始めました。
というのも、Windowsのホームディレクトリは C:\Users\<User名> なのですが
このディレクトリに特にファイルを置くつもりもありません。

ホームディレクトリをXamppのhtdocsディレクトリに変えたいなと思いました。

調査した結果、見つけた方法は3つ

※レジストリの操作は自己責任でお願いします

1. ショートカットの作成
「すべてのプログラム」→「アクセサリ」→「コマンドプロンプト」を右クリックして
作業フォルダにPathを記述する。

この方法はそのショートカットを実行しませんと意味がないので却下です。

2. %HOMEPATH% の変更

「ファイル名を指定して実行」に「regedit」と入力して実行
「編集」→「検索」から「HOMEPATH」と入力して検索
HOMEPATHの値を変更

この方法はコマンドプロンプト以外の機能にも影響を与えてしまいそうでしたので避けました。

3. initファイルの作成

要はcdコマンドを打つことを省略できれば良いわけですから、
コマンドプロンプトを起動したときに自動的にコマンドが実行されるのが理想的です。
というわけでinitファイルを作ってみました。

init.bat
@echo off
doskey ls=dir/w $*
doskey cat=type $*
doskey rm=del $*

cd Documents\Xampp\htdocs

各コマンドの説明は省略いたしますが、余計な出力を抑えることとLinuxでよく使うコマンドのうち
Windowsでコマンドの名称が違うもののAliasを作成しました。

init.batファイルを適当なディレクトリに保存したら方法2と同じ手順でレジストリエディタを開きます。
HKEY_CURRENT_USER\Software\Microsoft\Command ProcessorにAutoRunという新しいキーを作成し、
値に先ほど保存したbatファイルを指定すれば完了です。

私は3の方法を採用しました。


これにて、開発のたびにcdコマンドを1回打つ労力が削減できました。
満足ですw

github

自分の書いたコードをどのように保存したり公開しようか悩んでいたのですが、
試しにgithubを利用してみることにしました。

http://github.com/kakky0625/t.git

以下、導入手順メモ

  1. Git Clientをダウンロード
  2. Git Clientのインストール
  3. Git GUIを起動し、「ヘルプ」→「SSHの表示」よりSSHキーを生成
  4. githubにアクセスし、アカウントを作成する
  5. 新規レポジトリの作成
ここまででほぼ準備完了です。
後はあちらのページのヘルプを参考にしながら操作してください。

以下メモ。

ユーザ情報を追加しよう
git config --global user.name 'your name'
git config --global user.email you@example.com

aliasを追加しよう
git config --global alias.co checkout
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.last 'log -1 HEAD'

追加した情報は git config --list で確認できます。

リポジトリを取得しよう
gitでリポジトリを取得する場合はcheckoutではなくcloneです。

git clone <url>

これでリポジトリの取得ができます。

pushしよう
commitしたファイルがgithubに反映されないので悩んでいたのですが、
どうやらpushしないとgithubには反映されないという事でした。

詳しい使い方についてはこれから徐々に学んでいきます。

開発環境の準備

今までPHP一本で開発をしてきたのですが、
先日C++での開発に転向するよう命じられ、
今まで培ってきたものを忘れないためにもブログを再開することにしました。

まずは開発環境の準備から

1.xamppのダウンロード
2.xamppのインストール
3.http://localhost/xampp/ の表示確認
4.http://localhost/security/ で外部からの接続をシャットアウトするように設定
5.環境変数のPathの項目に C:\xampp\php を追加

以上で最低限の開発環境の準備は終了です。