PHP 将 self 作为类中的对象数组返回?
我正在使用 CodeIgniter 构建一个 php Web 应用程序,并且我正在尝试使用良好的 OO 实践 - 其中似乎有很多思想流派。我专门有一个 biography_model 类来与 MySQL 表交互。该数据模型具有一些表示表中列的类属性,但它也具有一些不在表中的属性,例如$image_url
。类构造函数接受一个可选的记录 ID 参数,然后该参数从表中获取该记录并通过调用 get_biography()
方法设置所有对象属性,包括 $image_url
属性不在表中。这样我就可以在控制器中实例化一个新的 biography_model 对象,并准备好所有有用的属性: $bio = new biography_model($id);
但是,当我们返回多个时,最好的方法是什么? - 表中记录的行结果集?对于每条记录,我还需要设置 $image_url
。我可以在控制器中执行此操作,方法是查询表中的记录列表,然后将每个 id 传递到新的 biography_model($id) 对象中。但随后我会遇到控制器绕过模型直接查询数据库的情况。
相反,我选择从biography_model 中返回biography_model 对象的数组。
例子:
class Biography_model extends Model
{
/**
* This model manages biography information in the 'biography_content' table.
* If a biography ID is passed in when instantiating a new object,
* then all class properties are set.
*/
protected $id;
protected $person_name;
protected $title;
protected $image_file_name;
protected $image_url;
protected $biography_text;
protected $active;
/**
* Constructor
*
* If an id is supplied when instantiating a new object, then
* all class variables are set for the record.
*/
public function __construct($person_id = NULL)
{
parent::Model();
if(isset($person_id))
{
$this->set_property('id',$person_id);
$this->get_biography();
}
}
/**
* Sets supplied property with supplied value.
*/
public function set_property($property, $value)
{
// Set image path if $value is the file name
if($property == 'image_file_name')
{
$this->set_property('image_url',$this->get_bio_img_url($value));
}
$this->$property = $value;
}
/**
* Gets requested property value.
*/
public function get_property($property)
{
return $this->$property;
}
/**
* Returns the biography thumbnail image URL
*/
public function get_bio_img_url($image_name)
{
return $this->config->item('parent_url').'assets/img/biography/'.$image_name;
}
/**
* Get one or more biography entries
*/
public function get_biography()
{
// If the ID is set then set model properties.
if($this->get_property('id'))
{
$this->db->where('id',$this->get_property('id'));
$query = $this->db->get('biography_content');
if($query->num_rows() == 1)
{
foreach($query->row() as $key => $value)
{
$this->set_property($key, $value);
}
}
}
// Otherwise return result set of all biographies
else
{
// Get the list of record ID's
$this->db->select('id');
$query = $this->db->get('biography_content');
if ($query->num_rows() > 0)
{
// New array to return result set
$biography_list = array();
// For each record, return a new biography_model object
foreach($query->result() as $value)
{
$biography_list[] = new biography_model($value->id);
}
}
return $biography_list;
}
}
}
// End of Biography_model Class
有用。但这是合理的做法吗?还有其他更容易被接受的方法吗?我敏锐地意识到我正在查询数据库两次,但我不确定有更好的方法来处理这个问题。欢迎所有建议!
谢谢,狼
I'm using CodeIgniter to build a php web application, and I'm trying to use good OO practices - of which there appears to be many schools of thought. I specifically have a class biography_model to interact with a MySQL table. This data model has some class properties representing the columns in the table, but it also has some properties not in the table such as $image_url
. The class constructor function accepts an optional record ID parameter which then fetches that record from the table and sets all object properties by calling the get_biography()
method, including the $image_url
property not in the table. This way I can instantiate a new biography_model object in the controller with all useful properties ready to go: $bio = new biography_model($id);
But, what is the best approach when we are returning a multi-row result set of records from the table? For each record I need to also set the $image_url
. I could do this in the controller, by querying the list of records in the table and then passing each id into the new biography_model($id) object. But then I would have a situation where the controller is directly querying the database bypassing the model.
Instead, I choose to return an array of biography_model objects from within the biography_model.
Example:
class Biography_model extends Model
{
/**
* This model manages biography information in the 'biography_content' table.
* If a biography ID is passed in when instantiating a new object,
* then all class properties are set.
*/
protected $id;
protected $person_name;
protected $title;
protected $image_file_name;
protected $image_url;
protected $biography_text;
protected $active;
/**
* Constructor
*
* If an id is supplied when instantiating a new object, then
* all class variables are set for the record.
*/
public function __construct($person_id = NULL)
{
parent::Model();
if(isset($person_id))
{
$this->set_property('id',$person_id);
$this->get_biography();
}
}
/**
* Sets supplied property with supplied value.
*/
public function set_property($property, $value)
{
// Set image path if $value is the file name
if($property == 'image_file_name')
{
$this->set_property('image_url',$this->get_bio_img_url($value));
}
$this->$property = $value;
}
/**
* Gets requested property value.
*/
public function get_property($property)
{
return $this->$property;
}
/**
* Returns the biography thumbnail image URL
*/
public function get_bio_img_url($image_name)
{
return $this->config->item('parent_url').'assets/img/biography/'.$image_name;
}
/**
* Get one or more biography entries
*/
public function get_biography()
{
// If the ID is set then set model properties.
if($this->get_property('id'))
{
$this->db->where('id',$this->get_property('id'));
$query = $this->db->get('biography_content');
if($query->num_rows() == 1)
{
foreach($query->row() as $key => $value)
{
$this->set_property($key, $value);
}
}
}
// Otherwise return result set of all biographies
else
{
// Get the list of record ID's
$this->db->select('id');
$query = $this->db->get('biography_content');
if ($query->num_rows() > 0)
{
// New array to return result set
$biography_list = array();
// For each record, return a new biography_model object
foreach($query->result() as $value)
{
$biography_list[] = new biography_model($value->id);
}
}
return $biography_list;
}
}
}
// End of Biography_model Class
It works. But is it a reasonable approach? Are there other more accepted methods? I'm keenly aware that I am querying the database twice, but I was not sure of a better way to handle this. All suggestions are welcome!
Thanks, Wolf
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
通常,职能部门最好只负责一份工作。你的 get_biography() 函数有 2 个:获取一份传记并获取所有传记。考虑将它们分成两个函数。此外,也不需要多个数据库访问。
另外,您可能想利用 php 的
__get
和__set
魔术方法:这将让您获得模型的属性,如下所示:
$bio->title
而不是$bio->get_property('title')
,同时提供一个稍后可以引入新逻辑的位置。Usually it's better for functions to have one job. Your get_biography() function has 2: get one biography and get all biographies. Consider splitting them up into 2 functions. Also there's no need for the multiple db access.
Also you might want to take advantage of php's
__get
and__set
magic methods:This will let you get properties on your model like this:
$bio->title
instead of$bio->get_property('title')
while at the same time provide a place you can introduce new logic later.使用数组来表示一组记录是一种完全有效的方法。
但是,属性
image_url
直接依赖于另一个属性的值,因此将其存储为单独的字段是没有意义的。只需即时计算即可,在您的情况下,您必须在get_property
方法中执行此操作。另一方面,模型真的应该负责处理 URL 吗?我不这么认为。模型外部应该有一个方法,它采用
Biography_model
对象并根据其image_file_name
生成图像的 URL。如果您已经有一些负责将控制器映射到 URL 的路由模块,则此代码可能应该放置在那里。Using an array to represent a set of records is a perfectly valid approach.
However the property
image_url
directly depends on the value of another property, so it doesn't make sense to store it as a separate field. Just calculate it on the fly, in your case you'd have to do that in theget_property
method.On the other hand should the model really be responsible for dealing with URLs? I don't think so. There should be a method outside the model that takes the
Biography_model
object and generates the URL of the image based on itsimage_file_name
. If you already have some routing module responsible for mapping controllers to URLs, this code should probably land there.