先日から「GnuCash」使って家計簿を付け始めたyukiです。
だいぶ長いこと複式簿記に触れていなかったので、思い出すのに一苦労でした。家計簿で「損益計算書」や「貸借対照表」、「キャッシュフロー」を見てみると新たな発見があっていいですね。是非オススメです。
さて今回は、先日の社内勉強会で行った「いまさらPHP5.3をあらためて見てみる」をレポートします。機能をサンプルコード交えてざっとチェックしていっただけですが、参考になれば幸いです。
参考:PHP 5.2.x から PHP 5.3.x への移行
新機能
新機能からチェックしていきます。まずは話題になっていた名前空間などから。名前空間
# global.php
namespace {
class MyProject
{
public function getName()
{
return 'global';
}
}
}
# unoh.php
namespace unoh {
class MyProject
{
public function getName()
{
return 'unoh';
}
}
}
# photo.php
namespace unoh\photo {
class MyProject
{
public function getName()
{
return 'photozou';
}
}
# machi.php
namespace unoh\machi {
class MyProject
{
public function getName()
{
return 'machi';
}
}
}
# sample.php
require 'global.php';
require 'unoh.php';
require 'photo.php';
require 'machi.php';
// requireした名前空間には影響を受けない
var_dump(__NAMESPACE__);
$a = new MyProject;
var_dump($a->getName());
// globalを指定してnewする
$a = new \MyProject;
var_dump($a->getName());
// unoh空間のクラスを指定してnewする
$a = new \unoh\MyProject;
var_dump($a->getName());
// 下位空間のクラスを指定してnewする
$a = new \unoh\photo\MyProject;
var_dump($a->getName());
$a = new \unoh\machi\MyProject;
var_dump($a->getName());
// エイリアス作成
use \unoh\photo\MyProject as photozou;
var_dump(new photozou);
// エイリアスでタイプヒンティングしたらどうなるか?
class TypeHint
{
public function hint(photozou $a)
{
var_dump($a);
}
}
$a = new TypeHint;
$photozou = new photozou;
$a->hint($photozou);
$photozou = new \unoh\photo\MyProject;
$a->hint($photozou);
以上のコードを実行した時、結果は次のようになります。
string(0) ""
string(6) "global"
string(6) "global"
string(4) "unoh"
string(8) "photozou"
string(5) "machi"
object(unoh\photo\MyProject)#2 (0) {
}
object(unoh\photo\MyProject)#1 (0) {
}
object(unoh\photo\MyProject)#3 (0) {
}
ほぼ予想通りでしたが、タイプヒンティングにエイリアスが利用できるのは便利な反面、混乱の元になるかもしれません。手元環境しだいですが、バックスラッシュもあまり違和感を感じませんでした。
遅延静的束縛
静的呼び出し時にstaticキーワードが使えるようになりました。実際の動作は以下のような感じです。# self.php
class A {
public static function who() {
echo __CLASS__ . "\n";
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__ . "\n";
}
}
B::test();
# static.php
class A {
public static function who() {
echo __CLASS__ . "\n";
}
public static function test() {
static::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__ . "\n";
}
}
B::test();
違いはClass Aのtestメソッド内での呼び出しです。それぞれselfがA、staticがBと表示されます。
ジャンプラベル (制限付きgoto)
素人にはお勧めできない諸刃の剣、一歩間違えるとスパゲッティコード生成機のgoto文です。
# goto.php
for ($i = 0; $i < 100; $i++) {
for ($j = 0; $j < 100; $j++) {
if ($i > 50 && $i === $j ) {
goto wall;
}
}
}
echo '超えられない壁';
exit;
wall:
echo '超えてしまった!';
結果は予想通り「超えてしまった!」と出ます。では次のコードはどうなるでしょうか?
# goto2.php
$photo = 'フォト蔵';
loop:
if ($photo === 'A') {
goto A;
} elseif ($photo === 'B') {
goto B;
} else {
goto C;
}
exit;
C:
echo 'C';
goto B;
exit;
A:
echo 'A';
goto loop;
exit;
B:
echo 'B';
goto A;
exit;
このくらいならまだ判別できますが、だんだんわかりにくくなってきました。ちなみにこれを実行するとCBACBACBA...と無限ループします。
# goto3.php
class myClass
{
public function jump()
{
goto out;
}
}
$v = new myClass;
$v->jump();
exit;
out:
echo 'OUT!';
これは次の出力になります。
Fatal error: 'goto' to undefined label 'out' in /home/edy/php5.3/goto/goto3.php on line 8
ご覧のとおりメソッドの内外に出入りはできないようです。
クロージャ (ラムダ/無名関数)
コールバックに無名関数が指定できるようになりました。
# callback.php
$system = array('leopard','vista');
$upgrade = array_map(function($value) {
if ($value === 'leopard') {
return 'snow '.$value;
} elseif ($value === 'vista') {
return 'windows7';
}
}, $system);
var_dump($upgrade);
ぱっと見がなんだかJavascriptっぽくなってますね。結果は以下の通りです。
array(2) {
[0]=>
string(12) "snow leopard"
[1]=>
string(8) "windows7"
}
スコープ外の変数を利用する場合は次のようになります。
# use.php
$args = 'B';
$patternA = function($value) use ($args) {
$args = 'C';
return "Value: $value Args: $args";
};
$patternB = function() use (&$args) {
$args = 'D';
};
var_dump($args);
var_dump($patternA('A'));
$patternB();
var_dump($args);
結果は以下の通りです。
string(1) "B"
string(16) "Value: A Args: C"
string(1) "D"
&の有無で挙動が代わるので注意が必要です。
他には以下のような変更がありました。便利なのが追加された印象ですね。
- マジックメソッド__callStatic、__invoke
- Nowdoc(静的なクラスメンバ/定数も)
- 定数 はクラス外const宣言
- 三項演算子 ?:
この中だと、とくに三項演算子に注意が必要です。式の結果がtrueであれば「式の結果」を、でなければ?:に続くものを返します。
非推奨関数
- call_user_method()
- call_user_method_array()
- ereg()
- ereg_replace()
- eregi()
- eregi_replace()
- session_register()
- session_unregister()
- session_is_registered()
- split()
- spliti()
もともと非推奨だったものが継続されているイメージですが、ereg系はまだ現役でコードに存在すると思いますので、注意が必要ですね。動かないわけではないので、今のところ実害はないと思います。
パラメータ変更
目に付いたのはこのあたりです。
- nl2br()
- is_xhtml が追加されました。
- round()
- mode が追加されました。
- json_encode()
- options が追加されました。
- json_decode()
- depth が追加されました。
- Exception::__construct
- previous が追加されました。ネストした例外補足の時など、以前の例外を追加して統合するため。
新クラス
日付・時刻
- DateInterval
- DatePeriod
DateTimeクラス自体も強化されたので、date()とかmktime()とかtime()とかで泥臭さが軽減されるかもしれません。個人的には嬉しい機能追加です。
Phar
- Phar
- PharData
- PharException
- PharFileInfo
SPL
Heap,Queue,Stack,FixedArray,ObjectStorageなどのデータ構造系が追加されています。
- FilesystemIterator
- GlobIterator
- MultipleIterator
- RecursiveTreeIterator
- SplDoublyLinkedList
- SplFixedArray
- SplHeap
- SplMaxHeap
- SplMinHeap
- SplPriorityQueue
- SplQueue
- SplStack
その他
その他細かくは以下のあたりが気になりました。
- SplFileInfo::getpathinfo() メソッドは、パス名に関する情報を返すようになりました。
- GD関数では、imagefilter() 関数を使ってモザイク効果を適用できるようになりました。
- var_dump() 関数の出力に private なオブジェクトメンバの値も含まれるようになりました。
- property_exists() 関数はプロパティのアクセス制限に関係なくプロパティの存在をチェックするようになりました(method_exists() と似た動作をします)
- getimagesize() 関数は、アイコンファイル (.ico) をサポートするようになりました。
なぜモザイクが...