PHP中的OOP方法

时间:2011-01-26 14:01:29

标签: php oop

我在程序上用PHP编程(这是一个单词吗?)大约五年了,并决定尝试OOP方法但遇到了一些概念/设计问题。假设您在程序中有一些模块,每个模块都可以列出,添加,编辑和删除实体。一个实体可以是..Dunno,用户,客户,产品等。

您如何设计类来操纵这些实体?

我想到了两种可能性:

  • 使用getUsersList,addUser,editUser,delUser
    等方法为每个实体创建类 这种方法似乎是资源消耗,因为在列表的脚本中,您只需要getUsersList和delUser方法,而在添加用户弹出脚本中,您只需要addUser方法,而在edit用户弹出脚本中只需要editUser方法。因此,您必须实例化一个对象,并且只使用其中的两个或一个方法......
  • 创建通用类:列出,添加,编辑和删除并为每个实体扩展它们,这样你只需要一次实例化一个类(你真正需要的那个)

提前致谢,

4 个答案:

答案 0 :(得分:5)

我会创建一个interface来定义您的列表,添加,编辑和删除方法。这为您提供了一个类“模板”。如果您的类(用户,客户端,产品等)实现此接口,则必须在这些类中定义接口中的方法。

这将为您提供类似的“API”,以访问实现您的界面的每个类的所有功能。由于每个列出的对象都包含不同的数据,因此方法的细节会有所不同,因而是分开的,但界面将是相同的。

<强>除了:

您在方法列表中包含“列表”会让我感到有些担忧。这似乎意味着您将对象视为用户,客户端,产品等的集合,其中很可能是表示单个用户的用户类,一个表示<的客户端类< em>单个客户等

另一方面,“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

无论如何,这就是我处理事情的方式。

答案 1 :(得分:2)

您需要创建一个可靠的架构和框架来管理您的数据模型。这并不容易,只会随着数据模型的增长而变得更加复杂。我强烈建议使用PHP框架(Symfony,CakePHP等),或者至少使用ORM(Doctrine,Propel等)。

如果你还想自己动手,我会从类似下面的架构开始。

您将需要一个用于单个记录操作的DbRecord类(如保存,删除等)。此DbRecord类将由特定实体扩展,并将为基本实体操作提供基础。

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();

现在,您需要一个用于表上批量操作的DbTable类(如读取所有实体等)。

class DbTable {
    public function readAll() {
        // read all
    }

    public function deleteAll() {
        // delete all logic
    }

    public function fetch($sql) {
        // fetch logic
    }

    // other table methods
}

class UserTable extends DbTable {
    public function validateAllUsers() {
        // validation logic
    }

    // ...
}

您可以从中执行批量/表操作:

$userTable = new UserTable();
$users = $userTable->readAll();

foreach ($users as $user) {
    // etc
}

代码体系结构是网站正确扩展的关键。将数据模型划分为适当的类和层次结构非常重要。

同样,随着您网站的增长,手动管理数据模型变得非常复杂。然后,当您真正看到PHP框架或ORM的好处时。

注意:DbRecordDbTable是任意名称 - 使用您喜欢的w / e名称。

答案 2 :(得分:1)

使用第一种方法,使用方法创建可重用对象。您只需编码一次就不浪费时间。

class User {
    function __construct() { /* Constructor code */ }
    function load($id) { ... }
    function save() { ... }
    function delete() { ... }
}

答案 3 :(得分:1)

你正在使用'普通类'(也称为基类,或抽象类,以防他们的行为需要在子类可以投入使用之前补充)。

OOP方法是将所有实体的所有行为放在基类中。

如果您使用类似于ActiveRecord的东西,那么您已经有了一个用于create-update-delete操作的通用(抽象)接口。使用它对您有利,并让您的基类仅在这些接口方法上运行。他们不需要知道他们正在更新产品或用户,他们只需要知道他们可以在实体上调用update()方法。

但即使不使用像AR框架那样功能强大的东西(如果你对一个非常灵活的ORM感兴趣,请查看Doctrine)。你可以使用接口来抽象行为。

让我举一个更详细的例子......


/**
 * 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'));

当然,还有很多需要改进的地方......例如您通常不希望每次在实体上调用fetch()时都进行查询,而是只查询一次并将结果对象存储在IdentityMap中,这也可以确保数据的完整性。

希望这会有所帮助,比我想要的更多,但我认为你试图解决这个问题是值得称赞的,而不会在问题上抛出一个框架:)