PHPプロ!TIPS+

1. O/Rマッパー - Piece_ORM

以前のTipsでEZPDOというO/Rマッパーについてご紹介しましたが、今回は別のO/RマッパーであるPiece_ORMをご紹介したいと思います。

Piece_ORMは、Piece Framework が提供しているシンプルなオブジェクトリレーショナルマッピングフレームワークで、Piece以外のシステムと組み合わせて使うことも出来ます。

また、この8月中だけで 0.5.0, 0.6.0, 0.7.0 と3回もリリースされ、非常に精力的な開発が行われています。

それでは早速使ってみましょう。

Piece_ORMのインストールは、PEARコマンドを使用できますので、非常に簡単です。

まずは、PEARチャンネルを追加します。

  $ pear channel-discover pear.piece-framework.com

次に、Piece_ORMパッケージをインストールします。この際、必須となるPEARパッケージも自動的にインストールされます。

  $ pear install piece/piece_orm-beta

そして、使用するデータベース用のMDB2ドライバをインストールします。例えば、MySQLを使用する場合は、

  $ pear install pear/mdb2_driver_mysql

PostgreSQLを使用する場合は、

  $ pear install pear/mdb2_driver_pgsql

のようになります。

今度は、作業用のディレクトリを作成します。

  $ mkdir piece_orm
  $ cd piece_orm
  $ mkdir -p cache config/mappers scripts imports/spyc data/sql

また、PHPでYAMLを扱うためのクラスであるSpycが必要になりますので、ダウンロードしてimports/spycへインストールします。

  $ cd imports
  $ wget http://prdownloads.sourceforge.net/spyc/spyc-0.2.5.tar.gz?download
  $ tar xzf spyc-0.2.5.tar.gz -C spyc
  $ cd ..

次に、以下の5つのファイルを作成します。なお、User.yamlは空っぽで構いません。

□config/piece-orm-config.yaml

- name: piece_orm
  dsn: mysql://user:password@hostname/piece_orm

□config/mappers/User.yaml

□scripts/insert.php

<?php
error_reporting
(E_ALL);
set_include_path(dirname(__FILE__) . '/../imports/spyc' PATH_SEPARATOR 
get_include_path());

require_once 
'Piece/ORM.php';
require_once 
'Piece/ORM/Error.php';

Piece_ORM_Error::pushCallback(create_function('$error''var_dump($error);
 return ' 
PEAR_ERRORSTACK_DIE ';'));
Piece_ORM::configure('../config''../cache''../config/mappers');

$mapper = &Piece_ORM::getMapper('User');
$user = &$mapper->createObject();
$user->firstName 'Tips';
$user->lastName 'PHPPro';
var_dump($mapper->insert($user));
?>

□scripts/find.php

<?php
error_reporting
(E_ALL);
set_include_path(dirname(__FILE__) . '/../imports/spyc' PATH_SEPARATOR 
get_include_path());

require_once 
'Piece/ORM.php';
require_once 
'Piece/ORM/Error.php';

Piece_ORM_Error::pushCallback(create_function('$error''var_dump($error);
 return ' 
PEAR_ERRORSTACK_DIE ';'));
Piece_ORM::configure('../config''../cache''../config/mappers');

$mapper = &Piece_ORM::getMapper('User');
var_dump($mapper->findAll());
?>

□data/sql/create_user.sql

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL auto_increment,
  `first_name` varchar(255) NOT NULL,
  `last_name` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
);

最後に、使用するデータベースを作成します。今回はMySQLを使用することにします。

  $ mysql -h hostname -u user -p
  mysql> create database piece_orm;
  mysql> Bye
  $ mysql -u user -p -h hostnmae piece_orm < data/sql/create_user.sql

これで準備ができましたので、スクリプトを実行してみましょう。

  $ cd scripts
  $ php insert.php
  int(1)
  $ php find.php
  array(1) {
    [0]=>
    &object(stdClass)#10 (3) {
      ["id"]=>
      string(1) "1"
      ["firstName"]=>
      string(4) "Tips"
      ["lastName"]=>
      string(8) "PHPPro"
    }
  }

特に問題が無ければ、insert.phpでデータが登録され、find.phpでそのデータの一覧が取得できます。

さて、スクリプトにはSQLが記述されていませんが、どのようなSQLが実行されているのでしょうか?

では、cacheディレクトリにある一番サイズの大きなファイルを覗いてみましょう。 SQL文やメソッドがずらっと並んでいるかと思います。fildAll()やinsert()はここに書かれたSQLが実行されています。

また、Piece_ORMは、マッパー定義ファイルによってSQLと任意のメソッドをマッピングできるという特徴をもっています。 それでは、User.yamlを次のように書き換えて、insert()のSQLを上書きしてみましょう。

□config/mappers/User.yaml

- name: insert
  query: INSERT INTO user (first_name, last_name) VALUES ($firstName, 'PHP Pro!')

では、再度実行してみます。

  $ php insert.php
  int(2)
  $ php find.php
  array(2) {
    [0]=>
    &object(stdClass)#10 (3) {
      ["id"]=>
      string(1) "1"
      ["firstName"]=>
      string(4) "Tips"
      ["lastName"]=>
      string(8) "PHPPro"
    }
    [1]=>
    &object(stdClass)#11 (3) {
      ["id"]=>
      string(1) "2"
      ["firstName"]=>
      string(4) "Tips"
      ["lastName"]=>
      string(8) "PHP Pro!"
    }
  }

無事、上書きしたinsertクエリが実行されました。もう一度cacheディレクトリのファイルを覗くと、SQLが書き換わっているはずです。

以上、駆け足のご紹介となりましたが、もっと詳細に書かれたドキュメントが用意されていますので、興味をもたれた方は試してみては如何でしょうか。

Piece_ORM短期集中コース
http://trac.piece-framework.com/piece-doc/wiki/ja/users/piece-orm/QuickStart/CrashCourseInPiece_ORM

2. オブジェクトもforeachで反復処理しよう

今回は、配列を使用したループを組むときに重宝するforeach文のもう一つの機能について紹介します。

このforeachですが、配列だけでなくオブジェクトの反復にも使用することが出来ます。(ただし、PHP5以上のバージョンでしか使えないので注意してください)

これなら、データを取り出すためにwhile文を使用しなくても、foreachを一行書くだけで簡単にイテレーターの処理をすることが出来るので、工数削減や可読性の向上などが可能です。

オブジェクトを引数にした場合、foreach(オブジェクト as メンバ変数名 => メンバ変数の値)となり、アクセス権限のあるメンバ変数を全てを取り出します。

では、早速サンプルを見てみます。

class HogeClass {
  public $hoge = "hoge";
  public $piyo = "piyo";
  public $fuga = "fuga";

  protected $foo = "foo";
  private $bar = "bar";

    function myIterator(){
        foreach($this as $key => $val){     //自身のインスタンスをforeachに入れて
         echo $key . " => " . $val . "<br>"; //出力
        }
    }

}
//以下、表示処理

$hoge = new HogeClass();

echo "クラス外からforeach<br><br>";

foreach($hoge as $key => $val){     //インスタンスをforeachに入れて
  echo $key . " => " . $val . "<br>"; //出力
}

echo "<br>";
echo "クラス内からforeach<br><br>";

$hoge->myIterator();

出力結果 ----------------

クラス外からforeach

hoge => hoge
piyo => piyo
fuga => fuga

クラス内からforeach

hoge => hoge
piyo => piyo
fuga => fuga
foo => foo
bar => bar

基本的にはメンバ変数を全て表示しますが、クラス外の場合は、protected,privateの変数にはアクセス権がないので表示しません。クラス内では、全ての変数にアクセス出来るので全て表示しています。

また、Iteratorインターフェイスを実装している場合は、その指示にしたがって取り出すことが出来ます。

例えば、以下のように値を最初から3文字だけ切り出す処理を加えると、

class HogeIterator implements Iterator {
  private $list = array();

  public function __construct($list){
    $this->list = $list;
  }

  public function rewind() {
    reset($this->list);
  }

  public function key() {
    return key($this->list);
  }

  public function current() {
    return substr(current($this->list), 0, 3); //ここで3文字切り出す
  }

  public function next() {
    return next($this->list);
  }

  public function valid() {

    return current($this->list) !== false;
  }
}

$data = array('hoge',
              'piyo',
              'fuga');
$i_hoge = new HogeIterator($data);

foreach($i_hoge as $key => $val){
  echo $key . " => " . $val . "<br>";
}

実行結果

0 => hog
1 => piy
2 => fug

このように出力を変化させることが出来ます。ですので、例えば、内部ではUNIXタイムスタンプで保持しておき、foreachで取り出すときだけ日本語形式にするなどの処理に使用できます。

このように、オブジェクトを使用する場合にもforeachは役立ちます。もし、機会があれば使用してみてはいかがでしょうか。

バックナンバーについて

TIPS-MLは、毎週金曜日に更新され、新しい記事が掲載されます。

Tipsꗗy[W 

Pick Up Q&A

Q
PHPのHTML埋め込み記述について
 このエントリーをはてなブックマークに追加 
A
$_POST["data"] == "男" ? $val = "checked" : $val = "" ; の意味は以下と同じです。 if($_POST["data"] == "男"){ $val = "checked; } e...

>>続きを読む

kende様のご指摘通り、三項演算子を使用する際には、コードの複雑度などを考慮する必要がありますね。書きやすさと共に可読性も追求したいところですね。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)