【问题标题】:Am I writing procedural code with objects or OOP?我是用对象还是 OOP 编写程序代码?
【发布时间】:2011-09-22 23:08:28
【问题描述】:

所以基本上我正在从过程编码飞跃到 OOP。 我正在尝试实现 OOP 的原则,但我有一种唠叨的感觉,我实际上只是在用 Objects 编写程序样式。

假设我有一个管道/椅子/打印机/任何东西的列表,它们都在我的单表数据库中列为产品。我需要构建一个 webapp,根据它们的类型显示整个列表和项目,重点是“正确”使用 OOP 及其范例。

这样做有什么问题吗:

     CLass Show
     {

      public function showALL(){
      $prep = "SELECT * FROM myProducts";
      $q = $this->db-> prepare($prep);     
      $q->execute();
      while ($row = $q->fetch()) 
          {
            echo "bla bla bla some arranged display".$row['something']       
          }
      }

然后简单地

$sth = new show();
$sth->showAll();

我还会实现更具体的显示方法,例如:

showSpecificProduct($id)->(当用户说点击其中一个链接时,$id 将通过 $_GET 传递,我们将拥有单独的 product.php 文件,该文件基本上只包含

include('show.class.php');
$sth = new show();
$sth->showSpecificProduct($id);

showSpecificProduct() 将同时执行选择查询和输出 html 以供显示。

因此,简而言之,我是继续处理它,还是我只是对类和对象进行过程编码。如果我做错了,还有关于解决它的任何想法/提示等?

【问题讨论】:

  • 一个好的开始是从单一职责原则的角度开始思考:en.wikipedia.org/wiki/Single_responsibility_principle('格式化 html 以供显示'可能被认为是一种责任)
  • 我认为这是一个非常好的问题。大多数人发现从一开始就很难理解 OOP,但它绝对值得努力。提问会让你从一开始就远离坏习惯和做法。
  • 谢谢大家,你解开了我心中的一些疑惑,并指出了我敢说正确的方向。我有很多东西要阅读和学习。 :)

标签: php oop procedural


【解决方案1】:

除了@Phil 和@Drew 描述的模型实践,我还敦促您将业务、数据和视图层分开。

我已经包含了一个非常简单的版本,需要在您的实现中对其进行扩展,但我们的想法是让您的 Db 选择与您的输出分开,并在控制器中几乎将两者“连接”在一起。

class ProductController
{
    public $view;

    public function __construct() {
        $this->view = new View;
    }

    public function indexAction() {
        $model = new DbProductRepository;
        $products = $model->fetchAll();

        $this->view->products = $products;
        $this->view->render('index', 'product');
    }
}

class View
{
    protected $_variables = array();        

    public function __get($name) {
        return isset($this->_variables['get']) ? $this->_variables['get'] : null;
    }

    public function __set($name, $value) {
        $this->_variables[$name] = $value;
    }

    public function render($action, $controller) {
        require_once '/path/to/views/' . $controller . '/' . $action . '.php';
    }
}

// in /path/to/views/product/index.php
foreach ($this->products as $product) {
    echo "Product ID {$product['id']} - {$product['name']} - {$product['cost']}<br />\n";
}

【讨论】:

    【解决方案2】:

    更合适的是实现repository pattern。一个示例界面可能是

    interface ProductRepository
    {
        public function find($id);
    
        public function fetchAll();
    }
    

    然后您将创建此接口的具体实现

    class DbProductRepository implements ProductRepsoitory
    {
        private $db;
    
        public function __construct(PDO $db)
        {
            $this->db = $db;
        }
    
        public function find($id)
        {
            // prepare execute SQL statement
            // Fetch result
            // return result
        }
    
        public function fetchAll()
        {
            // etc
        }
    }
    

    直接从方法或函数echo 通常是个坏主意。让您的方法返回适当的对象/数组/任何东西并使用这些结果。

    【讨论】:

      【解决方案3】:

      您在上面描述的场景似乎很适合 MVC

      在您的情况下,我将创建一个严格用于访问数据的类(选择产品类别或特定产品),然后让不同的文件(您的视图)获取输出并显示它。

      它可能看起来像这样:

      class Product_Model {
          public function find($prodId) { ... }
          public function fetchAll($category = '') { ... }
          public function search($string) { ... }
      }
      

      然后你可以在其他地方做:

      $products = new Product_Model();
      $list = $products->fetchAll(37); // get all from category 37
      
      // in true MVC, you would have a view that you would assign the list to
      // $view->list = $list;
      
      foreach($ilst as $product) {
          echo "Product ID {$product['id']} - {$product['name']} - {$product['cost']}<br />\n";
      }
      

      MVC 的基本原理是模型类只是表示来自某些数据源(例如数据库)的数据的对象。您可能有一个映射器,可以将数据库中的数据映射到数据对象和数据对象。然后控制器将从您的模型类中获取数据,并将信息发送到视图,在视图中处理实际的呈现。在控制器中拥有视图逻辑(html/javascript)是不可取的,直接与控制器中的数据交互也是如此。

      【讨论】:

        【解决方案4】:

        首先,您需要研究类自动加载。这样您就不必包含您使用的每个类,您只需使用它,自动加载器就会为您找到要包含的正确文件。

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

        每个类应该有一个单一的职责。您不会有一个连接到数据库并更改一些用户数据的类。相反,您将拥有一个将传递给用户类的数据库类,并且用户类将使用数据库类来访问数据库。每个功能也应该有一个单一的职责。永远不要有在函数名中加上“and”的冲动。

        您不希望一个对象知道另一个对象的属性。这将导致在一个类中进行更改以迫使您在另一个类中进行更改,并且最终很难进行更改。属性应该供对象内部使用。

        在您开始编写一个类之前,您应该首先考虑您希望如何使用它(请参阅测试驱动开发)。您希望代码在使用时看起来如何?

        $user = new User($db_object);
        $user->load($id);
        $user->setName($new_name);
        $user->save();
        

        既然您知道如何使用它,那么以正确的方式编写代码就容易多了。

        有机会时研究敏捷原则。

        【讨论】:

          【解决方案5】:

          一个经验法则是类名通常应该是名词,因为 OOP 是关于拥有与真实概念对象相对应的软件对象。类成员函数通常是动词,即可以对对象执行的操作。

          在您的示例中, show 是一个奇怪的类名。一种更典型的方法是创建一个名为 ProductViewer 的类,并使用一个名为 show() 或 list() 的成员函数。此外,您可以使用子类来获得专门的功能,例如特定产品类型的自定义视图。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-05-09
            • 1970-01-01
            • 2010-10-30
            • 1970-01-01
            • 1970-01-01
            • 2017-01-16
            • 1970-01-01
            相关资源
            最近更新 更多