【问题标题】:How to structure classes in PHP如何在 PHP 中构造类
【发布时间】:2012-09-30 04:48:10
【问题描述】:

我一直致力于在 PHP 中迁移到 OOP。我在 php.net 上阅读了解释,但我希望我能在这里得到一些具体的答案。

我尝试创建以下示例来说明我的问题。假设我有“数据库”、“产品”和“用户”类,如果用户有权访问,我想显示产品。

所以我将“Products”类称为“showProducts()”函数,该函数依次创建“User”类的实例,该实例创建“Database”对象的实例并检查用户访问级别。

如果用户有访问权限,那么“showProducts()”函数会创建“Database”对象的另一个实例,并查询数据库。

class Database{

   public function query(){ 
      //runs query here 
   }

   public function __construct() { 
      //sets up connection here 
   }

}

class User{

   public function checkAccess(){ 
      $db = new Database(); 
      $db->query( //pass in query to check access )
      //does stuff, then returns true or false
   }

}

class Products{

   public function showProducts(){

      $user = new User();

      if($user->checkAccess())
         $db = new Database(); 
         $db->query( //pass in query to get products )
      }

}

我希望有人能说明如何以正确的方式做到这一点。

我想要某种控制器类,它创建一个“数据库”对象,可供所有需要访问它的类使用,而无需创建“数据库”对象的多个实例。我想要用户类也一样,所以有一个所有类都可以访问的 $users 对象,而不必每次我需要在“用户”类中使用某些东西时都创建一个新对象。

如果我的问题不清楚,我深表歉意,并提前感谢您的任何回复!

感谢大家的回复!

【问题讨论】:

    标签: php oop class object


    【解决方案1】:

    当从过程式编程转向面向对象编程时,您应该掌握的不仅仅是如何构建类。 OOP 不是编写类,它是关于遵循 OOP 中的最佳实践、原则和模式。

    您不应该在另一个内部实例化新对象,您应该通过构造函数或 setter 方法给用户对象,他的用户依赖的数据库对象。这就是所谓的依赖注入。目标是通过构造函数或 setter 方法将对象提供给需要它们的类。并且它们应该从该类外部实例化,因此更容易配置类。并且在构建一个类时,您希望轻松查看该类具有哪些依赖项。你可以在这里阅读控制反转原理:IoC

    那么您的代码将如下所示:

    <?php
    
    // User object that depends on Database object, and expects it in constructor.
    
    class User
    {
        protected $database;
    
        public function __construct($database)
        {
            $this->database = $database;
        }
    
        // -- SNIP --
    }
    
    ?>
    

    现在要使用该用户类,您可以这样做:

    <?php
    
        $database = new Database($connParams);
        $user = new User($database);
    
    ?>
    

    你也可以使用依赖注入,使用 setter 方法来设置依赖,但是我让你自己去谷歌 :)

    就是这样,请阅读有关 Inversion of Controll 原理,以及有关 Dependency Injection 和 Dependency Injection Containers 的内容,这些是管理类的最佳方法。

    我见过很多“OOP”的 PHP 代码,实际上它们只是使用类作为功能命名空间 :) 所以要了解 OOP 的原理和模式。

    玩得开心! :)

    【讨论】:

    • 非常感谢您的回复!因此,如果我有另一个在用户类上引用的类,我也会将 $user 对象作为参数传入?
    • 是的,你可以!您可以通过任意数量的课程。如果对象确实需要该对象工作,您可以通过构造函数传递对象。如果对象是可选的,您可以通过 setter 方法传递它。一旦你得到复杂的依赖关系,那么你可以考虑使用依赖注入容器来描述依赖关系,容器将能够从其他对象组装对象并将其返回给你:) 你可以在这里阅读更多关于依赖注入和依赖注入容器的信息:fabien.potencier.org/article/12/…
    【解决方案2】:

    不要在构造函数或其他方法中实例化对象。将它们作为参数传递,最好在称为工厂的不同类中传递。这样可以轻松测试您的代码,也可以轻松创建对象。

    另外,不要尝试使用单例。这是“全局变量”的面向对象版本,您不想使用全局变量。它使您的代码测试变得非常困难,几乎不可能。

    观看此视频http://www.youtube.com/watch?v=-FRm3VPhseI,了解为什么使用单例是不好的。尤其是 19:00 的 CreditCard 例子值得一看。

    如果您真的想做到最先进,请查看“依赖注入”的概念。从本质上讲,将需要的东西从外部传递到类中是整个秘密,但是有些框架会自动为您执行此操作,因此您不必再自己编写工厂了。这些被称为“依赖注入容器”或“DIC”。

    【讨论】:

    • 非常感谢!现在谷歌工厂类。你知道关于为网站设置类结构的任何好的一般教程吗?我开始了解原理,但就实际实现而言,我还是有点迷茫。
    • 首先我建议你看看自动加载。有几个系统可以使这变得简单,但归结为在目录树中组织你的类 - 每个文件一个类 - 并相应地对齐类名,以便自动加载器,它只获取所需的类名作为参数可以构造类应该在的路径和文件名。看看 Zend 框架(1 或 2)作为一个活生生的例子。您也可能会了解其他人如何在那里命名他们的课程。
    【解决方案3】:

    要为所有代码创建一个对象,请使用Singleton 模式:

    class Database{
       private $db_descriptor;
    
       private function __construct(){
           /* connect and other stuff */
       }
       public static function getInstance(){
           static $instance;
           if($instance === null){
              $instance = new self();
           }
           return $instance;
       }
    }
    

    您可以对用户使用相同的技术,我说更多使用 php 5.4 您可以将 1 特征用于单例模式。 最后一个提示:当您使用数据库和其他繁重的东西时,请使用称为lazy initialization 的技术。当您提高 OOP 技能时,请查看 Doctrine Project,他们会大量使用该技术!

    【讨论】:

    • 实际上,我建议现在查看企业框架中的示例,以了解事情是如何完成的。您可能不需要立即使用,但它们会让您很好地了解如何构建事物。
    • Symfony2 和 Zend2 框架是唯一值得研究的框架 :) 我知道我会为此获得很多反对票。但是这两个是在 PHP 中学习正确 OOP 的最佳选择!
    • Symfony 1.x 或 Symfony 2 或 Zend Framework 将是我推荐的最佳实践。如果你真的想使用一个框架,那么对于你需要做的事情来说,这些可能会也可能不会过大,你可能想看看像 CakePHP 或 CodeIgniter 这样不那么复杂的东西。
    • @Limeni:不是来自我。但是对于简单的小型项目来说,使用其中任何一个的完整堆栈都可能是矫枉过正。不过,在架构方面,它们是我唯一推荐的“正确”做事方式的例子,哈哈。
    • 好吧,我之前已经使用过 Symfony 1.* 和 Doctrine 1.* - 这就是我在上面回答的原因。对我来说,他们不t very hard. I said that didnt 使用“企业框架”,因为我认为它类似于银行的处理系统。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-25
    • 1970-01-01
    • 2011-07-24
    相关资源
    最近更新 更多