PHP5 OOP类结构

时间:2012-07-28 08:39:25

标签: php oop class pdo

我知道有很多问题,我已经做了很多阅读。我想在我的项目中询问这个问题,看看你可能有什么建议。

我有很多很多类的Web应用程序,例如用户文章(我认为是主要的类)和较小的类,例如 images comments 。现在在页面上,比如说一篇文章,它可能包含 images comments 的许多实例。有道理吗?现在说一个文章页面,我调用一个静态方法,它返回一个文章对象的数组。

这是背景,所以问题就在这里。

由于构建了大量的应用程序,我开始意识到拥有包含设置和共享功能的核心系统类非常有用。因为我用一个新的核心类扩展了我的所有类。看似相对简单,快速实施。我知道CodeIgniter做了类似的事情。我现在觉得我的应用程序变得有点乱。

问题这是个好主意吗?创建核心实例正是我在调用文章实例时所需要的,但是当我使用静态方法创建多个实例,或者在页面上调用多个图像或注释时。我不必要地调用核心课程吗?实际上它只需要每页调用一次(例如构造函数定义了数据库中的各种设置,我不想每次都这样,每页只显示一次),但是所有类的所有实例都应该有权访问核心课程。听起来就像我想要单例方法,但我知道在PHP中浪费时间。

这是我的代码在这一点上看起来像的想法。我尽力保持简单。

class core {

    public function __construct(){
        ...define some settings which are retrieve from the database
    }

    public function usefulFunction(){
    }
}


class user extends core {

    public function __construct(){
        parent::__construct();
    }

    public function getUser($user_id){
        $db = new database();
        $user = /* Get user in assoc array from db */

        $this->__setAll($user);
    }

    public static function getUsers(){
        $db = new database();
        $users = /* Get users from database in assoc array from db */

        foreach($users as $user) {
             $arrUsers[] = new self();
             $arrUsers[]->__setAll($user);
        }

        return $arrUsers;
    }

    private function __setAll($attributes) {
        foreach($attributes as $key => $value)
        {
            $this->__set($key, $value);
        }   
    }

    public function __set($key, $value) {
         $this->$key = $value;
    }

}

我遇到的另一个问题是有效地使用/共享数据库连接。目前,需要数据库连接的类中的每个方法都会创建一个新的数据库实例,因此在页面上我可能会这样做5到10次。像依赖注入原理这样的东西听起来好多了。

问题现在,如果我将数据库的实例传递给新的用户类,我知道我需要这样的东西......

class user{
    protected $db;

    public function __construct($db){
        $this->db = $db;
    }

    ... etc
}

$db = new database();
$user = new user($db);

...但是当我想运行静态函数users :: getUsers()时,访问数据库实例的最佳方法是什么?我是否需要在每个静态方法中将其作为变量传递? (许多类中有许多静态方法)。它似乎不是最好的方式,但可能没有其他办法。

问题如果按照第1部分的建议将所有类扩展到核心类之外,我可以在那里创建数据库的实例并访问一些实例吗?

问题我还有各种包含函数(不是oop)的文件,就像帮助文件一样。这些访问数据库的最佳方式是什么?我再次在每个函数中创建一个新实例。我真的不想将db作为参数传递给每个人。我应该使用全局变量,将这些辅助文件转换为类并使用依赖注入或不同的东西吗?

我知道那里有很多建议,但关于PHP的大多数信息和教程都已过时,似乎并没有涵盖这个复杂的东西......如果你可以称之为复杂的?

有关如何最好地布局我的类结构的任何建议。我知道这似乎很多,但肯定这是大多数开发人员每天都面临的问题。如果您需要更多信息,请告诉我并感谢您阅读!

4 个答案:

答案 0 :(得分:1)

您可以从处理所有数据库查询的抽象类开始,然后将它们构造为对象。通过这种方式设置参数化查询很容易,并且它将标准化您与数据库交互的方式。它还会使添加新对象模型成为一块蛋糕。

http://php.net/manual/en/language.oop5.abstract.php

abstract class DB
{
  abstract protected function table();
  abstract protected function fields();
  abstract protected function keys();

  public function find()
  {
    //maybe write yourself a parameterized method that all objects will use...
    global $db; //this would be the database connection that you set up elsewhere.
    //query, and then pack up as an object
  }

  public function save()
  {
  }

  public function destroy()
  {
  }
}

class User extends DB
{
  protected function table()
  {
    //table name
  }  

  protected function fields()
  {
    //table fields here
  }

  protected function keys()
  {
    //table key(s) here
  }

  //reusable pattern for parameterized queries
  public static function get_user( $id )
  {
    $factory = new User;
    $params = array( '=' => array( 'id' => $id ) );
    $query = $factory->find( $params );
    //return the object
  }
}

您需要从公共配置文件进行数据库连接,并将其保留为此模式的全局变量。

显然,这只是表面上看,但希望它能给你一些想法。

答案 1 :(得分:1)

你在评论中问我应该详细说明为什么这是一个坏主意。我想强调以下内容来回答:

  

问问自己是否真的需要它。

根据需要做出设计决策,而不仅仅是因为可以做到这一点。在您的情况下,问问自己是否需要核心课程。正如你在评论中已经被问到你写的那样,你实际上并不是真的需要它,所以答案是明确的:这样做是不好的,因为它不需要,而且不需要它引入了很多副作用。

由于这些副作用,您不希望这样做。所以从零到英雄,让我们做以下演变:

您有两部分代码/功能。一部分确实发生了变化,而另一部分则是一些不变的基本功能(框架,库)。你现在需要把它们放在一起。让我们简化这一过程并将帧缩减为单个函数:

function usefulFunction($with, $four, $useful, $parameters)
{
    ...
}

让我们将应用程序的第二部分 - 更改的部分 - 减少到单个User类:

class User extends DatabaseObject
{
    ...
}

我已在此处介绍了一个小而重要的更改:User类不再从Core延伸,而是从DatabaseObject延伸,因为如果我正确读取您的代码,则其功能是代表数据库表中的一行,可能是用户表。

我已经做了这个改变,因为有一个非常重要的规则。当你在代码中命名某些东西时,例如一个类,使用说话,一个好名字。一个名字就是命名。名称Core绝对没有其他任何你认为重要的或一般的或基本的或内部的,或它是铁水。没有线索。因此,即使您为设计命名,也请选择一个好名字。我想,DatabaseObject这只是一个非常快速的决定,甚至不知道你的代码,所以我很确定你知道那个班级的真实姓名,你也有责任给它真正的名字。值得一个,慷慨。

但是让我们把这个细节放在一边,因为它只是一个细节,并没有那么多与你想要解决的一般问题有关。假设坏名称是症状,而不是原因。我们现在玩House博士并列出症状,但只是为了找到原因。

到目前为止发现的症状:

  • 多余的代码(甚至不需要写一个类)
  • 错误的命名

我们可以诊断:失调吗? :)

为了逃避这一点,总是做所需的事情并选择简单的工具来编写代码。例如,提供公共函数(框架)的最简单方法就像使用include命令一样简单:

 include 'my-framework.php';    
 usefuleFunction('this', 'time', 'really', 'useful');

这个非常简单的拖线脚本演示了:应用程序中的一个部分负责提供所需的功能(也称为加载),而其他部分正在使用它们(这只是我们从中知道的程序代码)第一天,对吧?)。

这是如何映射/缩放到更多面向对象的示例,其中User对象可能会扩展?完全一样:

include 'my-framework.php';
$user = $services->store->findUserByID($_GET['id']);

这里的区别仅在于my-framework.php内部加载了更多内容,因此通常更改的部分可以使用不会更改的内容。例如,可以提供代表服务定位器(此处为$services)或提供​​自动加载的全局变量。

你保持这个越简单,你的进步就越好,最后你将面临真正的决定。通过这些决定,您将更直接地了解有何不同之处。

如果您想要对“数据库类”进行更多讨论/指导,请考虑阅读有关如何在企业应用程序架构模式中处理这些内容的不同方法的非常好的章节>这有点是一个很长的标题,但它有一章很好地讨论了这个主题,并允许你选择一个如何轻松访问你的数据库的拟合模式。如果你从一开始就保持简单,那么你不仅进步更快,而且以后也更容易改变它们。

但是,如果你从一些复杂的系统开始,从基类扩展(甚至可能同时做多个事情),那么事情从一开始就不容易改变,这将使你更长时间地坚持这样的决定如你所愿。

答案 2 :(得分:1)

总结所有答案:

  1. 不要使用单一的“上帝”类作为核心。
  2. 最好使用创建工作的类列表。根据需要创建尽可能多的类。每个班级应负责单一工作。
  3. 不要使用单例,这是一种旧技术,不灵活,请改用dependecy injection container (DIC)

答案 3 :(得分:0)

首先,最好的办法是使用Singleton Pattern来获取数据库实例。

class Db{
protected $_db;

private function __construct() {
       $this->_db = new Database();
}

public static function getInstance() {
if (!isset(self::$_db)) {
    self::$_db = new self();
}
return self::$_db;
}
}

现在,您可以像db::getInstance();一样使用它。

其次,你试图在函数__setAll($attributes).

中发明一种名为Active Record pattern的自行车

第三,你为什么要在扩展Core的课堂上写这个东西?

public function __construct(){
    parent::__construct();
}

最后,类名应该大写。