2349


例えば

[code]

    $entry = Model_Article::find('all');
    
[/code]

のような形でfindすると、結果はいくつかのプロパティを持ったオブジェクトで返ってきますが、 データを利用する際に

[code]

    foreach($entry as $key => $val){
        echo $val['title'];
    }
    
[/code]

みたいに、配列として扱えてしまうのはどういう仕組なんでしょうか？


CC BY-SA 3.0
2014-12-17T00:05:46.507
1827
2014-12-22T03:28:22.923
2772
question
php
FuelPHPなどのORMの結果で返ってくるオブジェクトと配列について


FuelPHPのORMはここらへんですね。
<https://github.com/fuel/orm/blob/1.8/develop/classes/model.php#L27>

基本的に[ArrayAccess](http://php.net/manual/ja/class.arrayaccess.php)を実装しているので、オブジェクトでも配列のようにアクセスすることが出来るようになっています。

PHPは内部的にオブジェクトの要素へのアクセス方法を変える事ができるようになっています（zend_object_handlersというCの構造体が定義されています）

ArrayAccessを実装したオブジェクトに対して配列のようにアクセスされた際は、内部的にArrayAccessのInterfaceのメソッドをコールすることでオブジェクトを配列のように扱えるように作られています。

少し話は変わりますが、どうしても多次元の配列は扱いづらい（プロパティが持っているオブジェクトもArrayAccessを実装する必要が出てくる）、等実装上の制限はでてきてしまいますが一貫したアクセス方法が提供できるのでArrayAccessは便利です。


CC BY-SA 3.0
2014-12-17T01:35:44.707
1830
2014-12-17T01:35:44.707
3023
1827
answer


まず話をFuelPHPに限定し、「foreachで配列として利用する」という部分で回答すると、質問にある下記コード

[code]

    $entry = Model_Article::find('all');
    
[/code]

にて、`Model_Article::find('all')`からの呼び出しを追うと、最終的には`Query`クラスの`get()`メソッド、および`hydrate()`メソッドが呼ばれています。

<https://github.com/fuel/orm/blob/1.8/develop/classes/query.php#L1184>

このメソッドの実装を見てみると、次のように、単に該当モデルのインスタンス作った後、それを（普通に）配列に詰め込んで返しているようです。

[code]

        public function get()
        {
            ...
    
            $result = array();
            $model = $this->model;
            $select = $this->select();
            $primary_key = $model::primary_key();
            foreach ($rows as $id => $row)
            {
                $this->hydrate($row, $models, $result, $model, $select, $primary_key);
                unset($rows[$id]);
            }
            // It's all built, now lets execute and start hydration
            return $result;
    
        ...
    
        public function hydrate(&$row, $models, &$result, $model = null, $select = null, $primary_key = null)
        {
            ...
    
            if (is_array($result) and ! array_key_exists($pk, $result))
            {
                $result[$pk] = $obj;
            }
    
[/code]

ですから、FuelPHPの場合は「配列が返ってくるから」というのが質問の回答になります。

一方で、PHPには`ArrayAccess`インターフェイス、`Traversable`インターフェイス、および`Traversable`を継承した`Iterator`インターフェイスなどがあり、これを使うと、自分で定義するクラスのインスタンスを配列のように扱えるようになります。

フレームワークが持つメソッドの返り値をあたかも配列のように`foreach`で回して中身を取り出せるのは、この機能によります。

実際にこれらのインターフェイスを実装したクラスを定義する場合は、`IteratorAggregate`を使うと手早く済ませられることも多いです。

Doctrineなど他のORMでは、こういったインターフェイスを実装したクラスのインスタンスが返される、という風になっているものもあります。

中に入っている個別のオブジェクトに配列アクセスするのは、chobieさんの書かれた`ArrayAccess`だけになります。


CC BY-SA 3.0
2014-12-22T02:59:00.087
2349
2014-12-22T03:28:22.923
2014-12-22T03:28:22.923
5444
5444
1827
answer