[英]PHP. The best practices of creating objects
Let's say I have an entity (a stone) and I have a few more specific entities, that extend the basic enity - a talking stone for example, which have a few different properties and methods. 假设我有一个实体(一块石头),我有一些更具体的实体,它们扩展了基本的实体 - 例如,一个有说服力的石头,它有一些不同的属性和方法。 All the properties of a stone are stored in the database in the same table. 石头的所有属性都存储在同一个表中的数据库中。 All the specific properties of a specific object are stored serialized in the field "specific_options" of the table. 特定对象的所有特定属性都序列化存储在表的“specific_options”字段中。 I have the class "Stone", and the class "Talking_Stone", which extends the basic stone class. 我有“石头”课程和“Talking_Stone”课程,它扩展了基本的石头课程。 I need to create a stone object based on the data I get from the database. 我需要根据从数据库中获取的数据创建一个石头对象。
What is the best practice to emplement such thing? 实现这样的事情的最佳做法是什么?
What I've got so far: 到目前为止我得到了什么:
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';
...
}
...
}
But somehow, it doesn't feel quite right.. 但不知何故,它感觉不太对..
You want to use a repository class for this: 您想为此使用存储库类:
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;
}
}
The greatest advantage here is that you split your database logic from your model. 这里最大的优点是您可以从模型中分离数据库逻辑。 This is great as you get a clean model with no awareness of the database. 这很好,因为你得到一个没有数据库意识的干净模型。 And you're free to do queries however you like, also keeping them clean and separated. 而且你可以随心所欲地进行查询,也可以保持清洁和分离。
Then you can use this to fetch the stone with the given id in, for example, your controller: 然后你可以使用它来获取具有给定id的石头,例如你的控制器:
$factory = new StoneFactory();
$repository = new StoneRepository($factory);
$stone = $repository->findStoneById($id);
Fetching collections is just as easy: 获取集合同样简单:
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;
}
}
Sooner or later you might want to fetch some related objects. 迟早你可能想要获取一些相关的对象。 There are a few approaches you can take here. 您可以在这里采取一些方法。 The simplest one is to actually just fetch each type of object separately and build your model up in the controller. 最简单的方法是实际上单独获取每种类型的对象并在控制器中构建您的模型。 For example, if you wanted a Bag
object with related Stone
objects in it: 例如,如果您想要一个包含相关Stone
对象的Bag
对象:
$bag = $bagRepository->findBagById($bagId);
$stones = $stoneRepository->findStonesByBagId($bagId);
$bag->addStones($stones);
Another approach would be to use a join
and actually build the Bag
and the Stones
within BagRepository
. 另一种方法是使用join
并在BagRepository
实际构建Bag
和Stones
。 As it's a little bit more complicated, I'm not going to write it down here. 因为它有点复杂,我不打算在这里写下来。
You should just as well use the repository to insert/update/deleta the data in the database based on your model. 您还应该使用存储库根据您的模型插入/更新/删除数据库中的数据。 Again, it's just as simple as adding an insert
, update
and delete
methods which accept a Stone
object and persist it's data in the database. 同样,它就像添加一个接受Stone
对象并将其数据保存在数据库中的insert
, update
和delete
方法一样简单。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.