PHP中的OOP方法
我用PHP程序化编程(这是一个词吗?)已经五年了,我决定尝试OOP方法,但遇到了一些概念/设计问题。假设程序中有一些模块,每个模块都可以列出、添加、编辑和删除实体。实体可以是..dunno、用户、客户、产品等 您将如何设计类来操作这些实体 我想到了两种可能性:PHP中的OOP方法,php,oop,Php,Oop,我用PHP程序化编程(这是一个词吗?)已经五年了,我决定尝试OOP方法,但遇到了一些概念/设计问题。假设程序中有一些模块,每个模块都可以列出、添加、编辑和删除实体。实体可以是..dunno、用户、客户、产品等 您将如何设计类来操作这些实体 我想到了两种可能性: 使用getUsersList、addUser、editUser、delUser等方法为每个实体创建类 这种方法似乎消耗了资源,因为在列表的脚本中,您只需要getUsersList和delUser方法,而在add user弹出脚本中,您只
- 使用getUsersList、addUser、editUser、delUser等方法为每个实体创建类
这种方法似乎消耗了资源,因为在列表的脚本中,您只需要getUsersList和delUser方法,而在add user弹出脚本中,您只需要addUser方法,在edit user弹出脚本中,您只需要editUser方法。所以,你必须实例化一个对象,并且只使用它的两个或一个方法李> - 创建通用类:为每个实体列出、添加、编辑、删除和扩展它们,这样一次只需实例化一个类(您真正需要的类)
提前感谢,使用您的第一个方法,即使用方法创建可重用对象。这不是浪费时间,因为您只需编写一次代码
class User {
function __construct() { /* Constructor code */ }
function load($id) { ... }
function save() { ... }
function delete() { ... }
}
我将创建一个定义列表、添加、编辑和删除方法的工具。这将为您提供一个类“模板”。如果您的类(用户、客户机、产品等)实现了此接口,则必须在这些类中定义接口中的方法
这将为您提供一个类似的“API”,以访问实现接口的每个类的所有功能。由于列出的每个对象都包含不同的数据,因此方法的详细信息将不同,因此是分开的,但接口将是相同的
旁白:
你在方法列表中包含的“列表”让我有点担心。这似乎意味着您将对象视为用户、客户机、产品等的集合,其中最有可能存在表示单个用户的用户类、表示单个客户机的客户机类等
另一方面,“list”可以作为一个静态方法处理——一个不需要类实例就可以调用的方法
$bob = new User('bob');
$bob->add(); // Adds bob to the database
$fred = new User('fred');
$fred->add(); // Adds fred to the database
$users = User::list(); // Gives an array of all the users in the database
无论如何,这就是我处理事情的方式。您需要创建一个坚实的体系结构和框架来管理数据模型。这并不容易,而且随着数据模型的增长,这只会变得更加复杂。我强烈建议使用PHP框架(Symfony、CakePHP等),或者至少使用ORM(条令、推进等) 如果您仍然想自己开发,我将从一个类似于下面的架构开始 您需要一个用于单个记录操作(如保存、删除等)的
DbRecord
类。这个<代码> dBeords< /Cord>类将被特定的实体扩展,并为基本实体操作提供基础。
class DbRecord {
public function save() {
// save logic (create or update)
}
public function delete() {
// delete logic
}
// other record methods
}
class User extends DbRecord {
private $name;
private $email;
public function setName($name_) {
$this->name = $name_;
}
public function setEmail($email_) {
$this->email = $email_;
}
}
从中,您可以执行单个记录操作:
$user = new User();
$user->setName('jim');
$user->setEmail('jim@domain.com');
$user->save();
$userTable = new UserTable();
$users = $userTable->readAll();
foreach ($users as $user) {
// etc
}
您现在需要一个DbTable
类,用于表上的批量操作(如读取所有实体等)
从中,您可以执行批量/表格操作:
$user = new User();
$user->setName('jim');
$user->setEmail('jim@domain.com');
$user->save();
$userTable = new UserTable();
$users = $userTable->readAll();
foreach ($users as $user) {
// etc
}
代码体系结构是网站正确扩展的关键。将数据模型划分为适当的类和层次结构非常重要
同样,随着网站的发展,手动管理数据模型会变得非常复杂。这时,您将真正看到PHP框架或ORM的好处
注意:
DbRecord
和DbTable
是任意名称-使用您喜欢的w/e名称。您使用“通用类”(也称为基类,或抽象类,以防在使用它们之前,它们的行为需要子类的补充)
OOP方法将把所有实体共有的行为放在基类中
如果您使用类似于ActiveRecord的东西,那么您已经有了用于创建更新删除操作的通用(抽象)接口。利用这一点,让基类只在那些接口方法上操作。他们不需要知道他们正在更新产品或用户,他们只需要知道他们可以对实体调用update()方法
但是,即使不使用AR框架等功能非常强大的东西(如果您对非常灵活的ORM感兴趣,请查看条令…),您也可以使用接口来抽象行为
让我给你一个更详细的例子
/**
* Interface for all entities to use
*/
interface Entity {
static function newEntity();
static function fetch($id);
function save();
function setProperties(array $properties);
function delete();
}
/**
* A concrete product entity which implements the interface
*/
class Product implements Entity {
public $productId;
public $name;
public $price;
public $description;
/**
* Factory method to create a new Product
*
* @param integer $id Optional, if you have auto-increment keys you don't need to set it
* @return Product
*/
public static function newEntity($id=NULL) {
$product = new Product();
$product->productId = $id;
return $product;
}
/**
* Factory method to fetch an existing entity from the database
*
* @param integer $id
* @return Product
*/
public static function fetch($id) {
// make select with supplied id
// let $row be resultset
if (!$row) {
return NULL; // you might devise different strategies for handling not-found cases; in this case you need to check if fetch returned NULL
}
$product = new Product();
$product->productId = $id;
$product->name = $row['name'];
$product->price = $row['price'];
$product->description = $row['description'];
return $product;
}
/**
* Update properties from a propreties array
* @param array $properties
* @return void
*/
public function setProperties(array $properties) {
$this->name = $properties['name'];
$this->price = $properties['price'];
$this->description = $properties['description'];
}
public function save() {
// save current product properties to database
}
public function delete() {
// delete product with $this->productId from database
}
}
/**
* An abstract CRUD controller for entities
*/
abstract class EntityCrudController {
protected $entityClass = 'UNDEFINED'; // Override this property in child controllers to define the entity class name
protected $editTemplate = NULL; // Override this to set an edit template for the specific entity
protected $templateEngine; // Pseudo-Templating engine for this example
/**
* Display the edit form for this entity
* @param integer $entityId
* @return string
*/
public function editAction($entityId) {
// Fetch entity - this is not the most clean way to fetch, you should probably consider building a factory that encapsulates this.
$entity = call_user_func($this->entityClass, 'fetch', $entityId);
// Assign entity to your edit template, in this example I'm assuming we're using a template engine similar to Smarty
// You can generate the HTML output in any other way you might like to use.
$this->templateEngine->setTemplate($this->editTemplate);
$this->templateEngine->assign('entity', $entity);
return $this->template->render();
}
/**
* Update an existing entity
*
* @param integer $entityId
* @param array $postArray
* @return string
*/
public function updateAction($entityId, array $formArray) {
// Be sure to validate form data first here, if there are errors call $this->editAction() instead and be sure to set some error information
$entity = call_user_func($this->entityClass, 'fetch', $entityId);
$entity->setProperties($formArray);
$entity->save();
// Again, using our imaginary templating engine to display...
$this->templateEngine->setTemplate($this->editTemplate);
$this->templateEngine->assign('entity', $entity);
$this->templateEngine->assign('message', 'Saved successfully!');
return $this->template->render();
}
// Devise similar generic methods for newAction/insertAction here
}
/**
* Concrete controller class for products
* This controller doesn't do much more than extend the abstract controller and override the 2 relevant properties.
*/
class ProductCrudController extends EntityCrudController {
protected $entityClass = 'Product';
protected $editTemplate = 'editProduct.tpl';
}
// Usage example:
// Display edit form:
$controller = new ProductCrudController();
$htmlOutput = $controller->editAction(1);
// Save product:
$htmlOutput = $controller->updateAction(1, array('name' => 'Test Product', 'price' => '9.99', 'description' => 'This is a test product'));
当然,还有很多地方需要改进。。e、 g.您通常不希望每次对实体调用fetch()时都进行查询,而是只查询一次并将结果对象存储在中,这也确保了数据的完整性
希望这会有所帮助,比我预想的要多一些,但我认为,如果你试图解决这个问题而不在这个问题上抛出框架,这是值得称赞的:)是的,但这不是浪费资源吗?实例化整个对象并在只需要一半或更少的对象时将其保留在内存中?尝试将其扩展到更大的范围。@Catalin:OOP默认情况下比过程代码更庞大。看看ORM,它们的效率非常低。但是,它加快了开发速度并使代码更干净。是的,我也这么认为,但仔细想想……您可以为函数创建一个命名规则并按程序工作。创建一个user.utils.php,其中包含诸如user_load()之类的函数;用户_save();用户_delete()@卡塔林:当然可以,但是那样他们就不会在同一个物体上互动了。您必须在函数之间传递第二个对象。用户和用户应该是独立的实体,就像您可能希望执行的那样
User->delete()
,但您也可能希望Users->delete()
删除多个用户。。。正如您所说,用户
应该是一个集合,应该是可编辑的,并且应该具有length()
属性..而不是单个用户