それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

phpのクラスを連想配列に変える。

PHPのクラスと連想配列を相互変換する事を考えた。PHPのオブジェクをを連想配列にしたいと思った。

クラスと、配列のアクセスの違い

クラス変数の場合

$obj->user->email->domain

連想配列の場合

$obj["user"]["email"]["domain"]

となる。どっちが読みやすいか、どっちを使うべき?とか不毛な議論に巻き込まれたくないので、両方を使えるようにしたい。

get_object_vars の利用

可視変数がすべてペアでとれる。

<?php
class Foo{
  public $a= 1;
  public $b= 2;
  private $x = 0;
}
$foo = new Foo();
get_object_vars($foo);
array(1) {
  ["a"]=> int(1)
  ["b"]=> int(2)
}

これで出来る気がするけど、変数をコピーするタイミングが制御できない。

コピーしてからオブジェクト変わったらどうする

コピーしてからオブジェクトに変更があったら面倒ですよね。

そうか、オブジェクトを配列としてアクセスできるようにしたいと思います。

SPLで ArrayのInterfaceを実装することにした。

ArrayObjectを実装するか?
http://jp.php.net/manual/en/class.arrayobject.php
ただのIteratorであれば
http://jp.php.net/manual/en/class.emptyiterator.php
ArrayIteratorを実装するか
http://jp.php.net/manual/en/class.arrayiterator.php
ArrayAccessを実装するか?
http://jp.php.net/manual/en/class.arrayaccess.php

などの方法があげられる。

ArrayAccessを使うのが一番楽だった。

ArrayAccessを実装して、phpのオブジェクトを配列っぽく見せるのが面白そうだった。

<?php
ArrayAccess  {
/* Methods */
abstract public boolean offsetExists ( mixed $offset )
abstract public mixed offsetGet ( mixed $offset )
abstract public void offsetSet ( mixed $offset , mixed $value )
abstract public void offsetUnset ( mixed $offset )
 }

ArrayAccessを implemtns したクラスは配列とおなじになる。


実用例:PDOで取り出せるテーブルクラスに配列機能つけた。

<?pphp
/**
*   DBのレコード配列に、機能を追加するクラス
*/
class TableRecord implements ArrayAccess //クラスだけど配列として扱えるように
{
    public $fields;
    public $field_names;
    public $updated_fields=array();
    public $table_class = null;
    public function __construct($assoc_array=null, & $table_class_instance=null){
        if($assoc_array && is_array($assoc_array)==false){throw new Exception("引数には連想配列を入れる。");}
        $this->fields = is_array($assoc_array)? $assoc_array:array();
        $this->table_class = ($table_class_instance)? $table_class_instance :null;
    }
    public function  offsetExists ( $k ){
        return isset($this->fields[$k]);
    }
    public function  offsetGet ( $k ){
        if( $k && isset($this->fields[$k]) ){
            return $this->fields[$k];
        }else{
            return null;
        }
    }
    public function  offsetSet ( $k,$v ){
        if( $k==null || !in_array($k, $this->field_names ) ) {
            throw new Exception("保存できるのはテーブルカラム名だけです");
        }
        if( isset($this->fields[$k]) && $this->fields[$k] == $v ){
            return; //変更なしは何もしない。
        }
        if( array_key_exists($k,$this->fields ) ) {
            array_push($this->updated_fields,$k);//更新の時は、更新であることをメモする。
        }
        $this->fields[$k] = $v;
    }
    public function offsetUnset($k){
        unset($this->fields[$k]);
    }
    public function to_array(){
        return array_diff($this->fields, array(""));
    }
    public function dirty(){
        return sizeof($this->updated_fields) > 0;
    }
    public function to_array_only_updated_filed(){
        if(!$this->dirty()){return false;}
        $a = $this->updated_fields;
        $a[] = "id";
        $a = array_flip($a);
        foreach($a as $k=>$v){
            $a[$k] = $this->fields[$k];
        }
        return $a;
    }
    public function table_class_name(){
        return str_replace("Record","",get_class($this->table_class));
    }
    public function save(){
        $table = $this->table_class;
        if($this->dirty()){
            return $table->update($this);
        }else{
            $id= $table->insert($this);
            if(!$this["id"]){
                $obj = $table->find($id);
                $assoc_array = $obj->fields;
                $this->fields = $assoc_array;
            }
            return $id;
        }
    }
    public function delete($force=false){
        if(!$this["id"]){return;}
        $this->table_class->delete($this["id"],$force);
        unset($this->fields);
    }
}