PHP. 创建对象的最佳实践

4
假设我有一个实体(一块石头),我还有一些特定的实体,扩展了基本实体 - 例如,一个会说话的石头,它具有一些不同的属性和方法。所有石头的属性都存储在同一个表中的数据库中。特定对象的所有特定属性都序列化存储在表的“specific_options”字段中。 我有“Stone”类和“Talking_Stone”类,后者扩展了基本的石头类。 我需要根据从数据库获取的数据创建一个石头对象。
如何最好地实现这样的事情?
目前为止,我已经得到了什么:
class Stone_Data {
    ...
    public static function get_item( $id ) {
            $sql = 'SELECT * FROM `' . self::$table . '` WHERE `id`=' . ( int ) $id;
            $item = self::$db->get_row( $sql );
            return $item;
    }
    ...
}

class Stone_Factory {
    ...
    public static function create( $id = null ) {
            // if the stone's type is set
            if ( !is_null( $id ) && !is_null( $data = Stone_Data::get_item( $id ) ) && !empty( $data['type'] ) ) {
                    // create a stone of this type
                    $class_name = ucfirst( $data['type'] ) . '_Stone';
                    return new $class_name( $data );
            }
            // otherwise create a basic stone
            return new Stone;
    }
    ...
}

class Stone {
    private $data = array(
        ...
            'specific_options'  => '',
        ...
    );
    ...
    public function __construct( $data = array() ) {
            $this->set( $data );
    }
    ...
    public function __set( $name, $value ) {
            if ( array_key_exists( $name, $this->data ) ) {
                    // serialize if the value is an array or an object
                    if ( is_array( $value ) || is_object( $value ) ) {
                        $value = serialize( $value );
                    }
                    $this->data[$name] = $value;
            }
    }
    public function set( $data = array() ) {
            foreach ( $data as $key => $value ) {
                    // serialize if the value is an array or an object
                    if ( is_array( $value ) || is_object( $value ) ) {
                        $data[$key] = serialize( $value );
                    }
            }
            $this->data = array_merge( $this->data, $data );
            return $this;
    }
    ...
}
class Talking_Stone extends Stone {
    ...
    public function __construct( $data = array() ) {
        parent::__construct( $data );
        // $this->type = 'talking'
        $this->specific_options->language = 'French';
        ...
    }
    ...
}

但是,不知怎么的,感觉还不太对劲...
1个回答

6
您想要为此使用存储库类:
class StoneRepository
{
    private $stoneFactory;

    public function __construct(StoneFactory $factory) {
        $this->stoneFactory = $factory;
    }

    /**
     * @param integer $id
     * @return Stone
     */
    public function findStoneById($id) {
        // Fetch your data from the database
        $row = ...;

        // Use the factory to create a new stone from the data
        // that has already been fetched
        $stone = $this->stoneFactory->create($row);

        // Return the new stone
        return $stone;
    }
}

这里最大的优势是将数据库逻辑与模型分离。这非常好,因为您可以获得一个没有意识到数据库的干净模型。您可以自由地按照任何方式查询数据,并保持它们的清洁和分离。
例如,在控制器中,您可以使用此功能来获取给定id的记录。
$factory = new StoneFactory();
$repository = new StoneRepository($factory);

$stone = $repository->findStoneById($id);

获取集合

获取集合同样非常容易:

class StoneRepository
{
    ...

    public function findAllStones() {
        // Again, fetch the data
        $rows = ...;

       // Transform each row into a Stone object
        $collection = array_map(function ($row) {
            return $this->stoneFactory->create($row);
        }, $rows);

        return $collection;
    }
}

返回带有关系的对象

迟早你会想要获取一些相关的对象。这里有几种方法可供选择。最简单的方法是实际上只是分别获取每种类型的对象,并在控制器中构建你的模型。例如,如果你想要一个带有相关的Stone对象的Bag对象:

$bag = $bagRepository->findBagById($bagId);
$stones = $stoneRepository->findStonesByBagId($bagId);

$bag->addStones($stones);

另一种方法是使用“join”实际在“BagRepository”内构建“Bag”和“Stones”。由于它有点复杂,我不会在这里写下来。
CRUD
您应该同样使用存储库根据您的模型在数据库中插入/更新/删除数据。同样,只需添加“insert”,“update”和“delete”方法即可接受一个“Stone”对象并将其数据持久化到数据库中。

好的,干净简洁明了 :) - dbf
嗯...看起来就是我一直在寻找的。感谢您的答案。再问几个愚蠢的问题:我可以使用存储库类来获取石头集合吗?我应该如何处理数据管理器类(Stone_Data)这个数据抽象层?我应该用存储库类替换它吗?我是否也应该使用存储库类进行CRUD操作? - c00x
基本上是的,是的和是的。我稍微扩展了一下我的回答,为您提供收集和建立关系的想法。对于CRUD,我没有添加示例,因为它基本上是相同的,但如果您需要,我会添加它。 - Kuba Birecki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接