【问题标题】:PHP: Real world OOP examplePHP:真实世界的 OOP 示例
【发布时间】:2010-11-23 12:54:25
【问题描述】:

我正在努力学习 OOP。我正在阅读的书中所谓的“现实世界”示例没有帮助。

PetCarHuman 等所有示例都不再帮助我了。我需要真实的例子,比如注册、用户个人资料页面等。

一个例子:

$user->userName = $_POST['userName'];//save username
$user->password = $_POST['password'];//save password
$user->saveUser();//insert in database

我也看过:

$user->user = (array) $_POST;

在哪里:

private $user = array();

将所有信息保存在一个数组中。

在同一类中

$user->getUser($uid);
// which sets the $this->user array equal to mysqli_fetch_assoc() using 
//the user id.

是否有在许多不同的 php 应用程序(注册、登录、用户帐户等)中实现 OOP 的实际示例?

【问题讨论】:

标签: php oop


【解决方案1】:

正如 astropanic 所说,您可以查看一个好的 PHP 框架或库的源代码。我推荐Zend Framework,它非常模块化,并且具有出色的专业设计。我会说这是一段非常好的面向对象的 PHP 代码。

不过,我认为从大量生产代码中学习并不是那么容易,因为它并不是真正用来教你任何东西的。但是,如果您想要真实的面向对象的 PHP 代码,Zend 框架(或 Symfony,或者可能是 CakePHP)可能是要走的路。

【讨论】:

    【解决方案2】:

    我建议你现在远离任何框架,如果你不了解 OOP,那么深入研究 zend 或任何其他框架都太过分了。

    PHP OOP 很有趣...哈哈很有趣,因为它受到支持,但 PHP 不像 java 或 c# 那样是一种 OOP 语言。

    只是为了强调我的陈述的简短示例:

    // define class
    class User {
    // define properties and methods
    public $name = "";
    }
    // instantiate class
    $user = new User; // or new User() or new user, it's all the same
    echo $user->name;
    

    但如果您想“即时”执行 OOP,您可以执行以下操作:

    $user = (object) array('name' => 'Peter');
    

    然后

    $user->name;
    

    但是您可以像在 java 或 c# 中一样使用 OOP,但不能使用相同的扩展 - 请记住,像 wordpress 和 drupal 这样的流行系统不是纯 OOP!但是你也可以在 PHP 中进行继承和其他类 OOP 的工作。

    【讨论】:

    • 我很抱歉,但$user = (object) array('name' => 'Peter'); 不是 OOP - 甚至正如你所说的“OOP on the fly”。那只是一个对象。使用对象!= OOP。显然,对象的使用是 OOP 的一个组成部分,但它的WAY远不止于此。
    【解决方案3】:

    OOP 不仅仅是关于单个类的外观和操作方式。它还涉及一个或多个类的实例如何协同工作。

    这就是为什么你会看到这么多基于“汽车”和“人”的例子,因为它们实际上很好地说明了这一原则。

    在我看来,OOP 中最重要的一课是封装多态性

    封装:以简洁、合乎逻辑的方式将数据和作用于该数据的逻辑耦合在一起 多态性:一个对象看起来像和/或行为像另一个对象的能力。

    一个很好的现实世界的例子就是目录迭代器。这个目录在哪里?也许它是一个本地文件夹,也许它像 FTP 服务器一样是远程的。谁知道呢!

    这是一个演示封装的基本类树:

    <?php
    
    interface DirectoryIteratorInterface
    {
        /**
         * @return \Traversable|array
         */
        public function listDirs();
    }
    
    abstract class AbstractDirectoryIterator implements DirectoryIteratorInterface
    {
        protected $root;
    
        public function __construct($root)
        {
            $this->root = $root;
        }
    }
    
    class LocalDirectoryIterator extends AbstractDirectoryIterator
    {
        public function listDirs()
        {
            // logic to get the current directory nodes and return them
        }
    }
    
    class FtpDirectoryIterator extends AbstractDirectoryIterator
    {
        public function listDirs()
        {
            // logic to get the current directory nodes and return them
        }
    }
    

    每个类/对象都有自己的检索目录列表的方法。数据(变量)与使用数据的逻辑(类函数,即方法)耦合。

    但故事还没有结束 - 还记得我说过 OOP 是关于类的实例如何协同工作,而不是任何单个类或对象吗?

    好的,让我们用这些数据做点什么——把它打印到屏幕上?当然。但是怎么做? HTML?纯文本? RSS?让我们解决这个问题。

    <?php
    
    interface DirectoryRendererInterface
    {
        public function render();
    }
    
    abstract class AbstractDirectoryRenderer implements DirectoryRendererInterface
    {
        protected $iterator;
    
        public function __construct(DirectoryIteratorInterface $iterator)
        {
            $this->iterator = $iterator;
        }
    
        public function render()
        {
            $dirs = $this->iterator->listDirs();
            foreach ($dirs as $dir) {
                $this->renderDirectory($dir);
            }
        }
    
        abstract protected function renderDirectory($directory);
    }
    
    class PlainTextDirectoryRenderer extends AbstractDirectoryRenderer
    {
        protected function renderDirectory($directory)
        {
            echo $directory, "\n";
        }
    }
    
    class HtmlDirectoryRenderer extends AbstractDirectoryRenderer
    {
        protected function renderDirectory($directory)
        {
            echo $directory, "<br>";
        }
    }
    

    好的,现在我们有几个用于遍历和呈现目录列表的类树。我们如何使用它们?

    // Print a remote directory as HTML
    $data = new HtmlDirectoryRenderer(
      new FtpDirectoryIterator('ftp://example.com/path')
    );
    $data->render();
    
    // Print a local directory a plain text
    $data = new PlainTextDirectoryRenderer(
      new LocalDirectoryIterator('/home/pbailey')
    );
    $data->render();
    

    现在,我知道你在想什么,“但是彼得,我不需要这些大类树来做这件事!”但如果你这么认为,那么你就错过了重点,就像我怀疑你一直在用“汽车”和“人”的例子一样。不要专注于示例的细节 - 而是尝试了解这里发生了什么。

    我们创建了两个类树,其中一个 (*DirectoryRenderer) 以预期的方式使用另一个 (*DirectoryIterator) - 这通常称为合同*DirectoryRenderer 的实例不关心它接收到哪种类型的 *DirectoryIterator 实例,*DirectoryIterator 的实例也不关心它们是如何呈现的。

    为什么?因为我们就是这样设计它们的。他们只是相互连接并工作。 这是实际的 OOP

    【讨论】:

    • 有没有给用户的例子??我希望有一个管理和身份验证的例子。如果有人知道某个地方,我将不胜感激。
    • @Peter Bailey 不幸的是我的问题已经结束,但如果你能帮助我this question(link here),我会很高兴
    • 这很好,但如果它也能显示实际的多态性,那就更好了。组合优于继承。渲染也可以是接口中的存根。
    【解决方案4】:

    购买一本《PHP 和 Mysql 日常应用傻瓜》之类的书。

    我知道它是旧的 [2005],但它在 Mysqli 面向过程和面向对象中显示了用户登录、论坛、购物车等的概念。

    它帮助我学习了面向对象的 PHP,我研究了很多。物有所值。

    OOP 很像将程序的各个部分组合成可重用的部分。对你说实话并不难,它只是将你的函数打包到类中的想法。

    OOP 的真实世界迷你示例如下:

    类数据库
    班级会议
    类网络表单
    班级电子邮件

    类帐户(以下示例函数)
    功能选择帐户
    功能检查密码
    功能检查用户名
    函数创建帐户

    我希望你坚持下去,PHP 6 将被重新设计以比以往更支持 OOP。

    祝你好运!

    【讨论】:

      【解决方案5】:

      我在 PHP OOP 方面还没有走多远,但是我越深入它就越容易。对象示例只是为了让您了解 OOP 的工作原理。我之前了解并经历过,OOP 只是关于属性和方法(普通变量和函数)。我自己使用我的教程中的示例在真正的 OOP 中编程,不一定必须在现实世界中。这就像被勺子喂食一样,你永远不会理解 OOP 并且很容易忘记。我的建议学会理解。如果你理解了,你可以做任何事情,并且会意识到 OOP 的力量。我下载了这本书,我想你也应该下载。但这就像有人为您构建您的应用程序一样......

      Here PHP 和 Mysql 日常应用傻瓜一书的链接

      【讨论】:

        【解决方案6】:

        虽然我知道这个问题已经得到解答,但我觉得我可以在这里增加价值。

        我不认为你应该使用 PHP 作为编程语言来学习 OOP。如果你想学习 Web 应用程序的 OOP,你真的应该看看 C# 或 Java。一旦你学会了 OOP,那么你就可以将这些知识应用到 PHP 中。我曾经学习 OOP 的一本书的一个例子是 Big Java by Cay S. Horstmann

        我为什么这么说???因为实际上有数百万关于如何做事的 PHP 示例,但是关于如何正确编程的示例并不多。除此之外,PHP 允许您走许多捷径,这对于 Java 之类的来说是不可接受的。因此,如果你用 Java 头脑编写 PHP,那么我相信你会成为一个更强大的程序员。 OOP 不是特定于语言的,它是一种编程范式。

        如果您必须使用 PHP 学习 OOP,那么我建议您查看 github 公共存储库中的一些真实源代码。您可以在 packagist.org 中搜索它们。如果它们是一个不错的公共存储库,它们将包含一个 readme.md 文件,该文件将向您展示如何使用作曲家包。例如 https://github.com/moltin/laravel-cart 是一个购物车包的示例,您可以在应用程序中使用它。请注意,您无需查看包源代码即可了解包的作用。包已经写好了,你不关心它们是如何工作的,但是你使用它们,所以你只需要知道如何使用它们。这正是 OOP 的意义所在。

        我不关心购物车类如何将商品添加到购物车中,我只想创建一个新的购物车并向其中添加一些东西。

        但是,您正在做的是深入研究源代码,作为了解 OOP 工作原理的工具。

        除此之外,可能更重要的是,对于 Web 应用程序开发,我会研究 MVC 设计模式。

        MVC 设计模式代表模型、视图、控制器。在 Web 应用程序的情况下,模型负责为数据库建模,视图负责向用户显示内容。控制器负责与模型交互并处理用户输入。

        然后我认为您应该尝试在本地计算机上安装Laravel Framework 或其他“体面的现代框架”。为什么我说现代,因为现代框架要求最低 PHP 版本为 5.3+,这意味着您机器上的 PHP 将支持真正的 OOP,类似于您从 Java 之类获得的 OOP。

        有许多教程将向您展示如何在 laravel 中构建 Web 应用程序。马上,你会看到当你创建一个控制器时,你扩展了一个 BaseController。当你创建一个模型时,你扩展了 Eloquent。这意味着您将已经在代码中使用多态性。你会看到通过使用类,它们被封装了,你会看到每个类都有一个特定的角色。

        当您想与数据库交互时,您将首先在控制器方法中创建一个new Model 对象。随着您开始了解更多,您将开始学习如何将依赖项注入控制器,然后学习如何转储模型并创建存储库和程序到接口。

        Dale Rees 的《https://leanpub.com/codebright》是一本适合初学者学习 Laravel 的书。大约 2 周前,我在 Laravel 聚会上认识了 Dale。

        此外,随着您越来越熟练地构建 Web 应用程序,您将开始学习如何将以下原则应用到您的编程中:

        • 单一职责原则
        • 开闭原则
        • 里氏替换原则
        • 接口隔离原理
        • 依赖倒置原则

        【讨论】:

          【解决方案7】:

          我还建议查看我的包装器Arrayzy。它是一个原生 PHP 数组易于操作的 OOP 库。

          因此,如果您使用原生 PHP 数组函数 - 您可以在 OOP 中做同样的事情,Arrayzy 可以帮助您,例如:

          // Functional programming:
          $array = ['a', 'b', 'c'];
          $resultArray = array_merge($array, ['c', 'd']);
          

          // Object-oriented programming:
          $obj = Arrayzy\MutableArray::create(['a', 'b', 'c']);
          $obj->mergeWith(['c', 'd']);
          $resultArray = $obj->toArray();
          

          在这两种情况下,结果数组都是:

          Array(
              0 => 'a'
              1 => 'b'
              2 => 'c'
              3 => 'c'
              4 => 'd'
          )
          

          检查mergeWith 方法(或其他方法)如何在后台工作。

          我认为这是一个很好的例子,它表明几乎所有 功能 代码都可以用 OOP 代码替换,就像在这个库中一样。但是使用 OOP,您会得到更多,您还可以查看Functional programming vs OOP 问题以了解更多详细信息,了解它的优缺点。

          【讨论】:

            【解决方案8】:

            你是对的,你在网上找到的 99% 的教程都太基础了,而且没有任何意义。我对任何尝试学习面向对象编程的人的建议是:

            找到一些你在过程编程中编写的代码,并尝试将其转换为 OOP。

            把你所有的变量变成一个类的属性,找到一个合适的类名。如果你有函数的话,然后把你所有的函数都放在一个类中。如果您编写代码时没有使用函数,请先尝试将代码转换为一组函数。找到合适的函数名,函数应该定义一段代码的作用。一旦你有你的函数将它们移动到一个类中。

            我会给你一个简单的分页代码示例,我将其转换为可重用的分页类。在 youtube 上找到完整的教程:https://www.youtube.com/watch?v=X38IRlyY_ww&t=91s,源代码的链接在描述框中

            class Paginator{
            
                /*the class need to know the current page to calculate the offset
                   the offset tell my sql how many rows to skip */
               private $current_page;
               //the limit is the number of results to display per page
               private $limit;
               /*pagination links to display below the results with next 
               and previous button*/
               private $pagination_links;
               //the last page of your pagination links 
               private $last_page;
               .
               . etc
            
                public function __contruct($number_of_rows_found,$results_to_display_per_page){
            
                  //the paginator uses the number_of_rows_found to determine the last page 
                   $this->last_page = $number_of_rows_found/$results_to_display_per_page;
                      //get the current page, set it to 1 by default
                     $this->current_page = isset($_GET['page']) ? ($_GET['page'] : 1;
            
                }
            
               public function generate_pagination_links(){ 
                      this method uses the last_page property to generate pagination links
                       if the last page is 3, this will give you 3 pagination links
                     for ($page = 1; $page <= $this->last_page; $page++) {
                        //use
                     }
               }
            public function get_offset_and_limit(){
                 //this method calculates the offset based on the current page
                  return "LIMIT $this->per_page OFFSET ".($this->page - 1) * $this->per_page;
             }
            .
            .
            .etc
            }
            }
            

            然后要使用分页类,你创建它的一个新实例,并传递 每页要显示的结果数,以及返回的结果数 通过您的查询作为参数。分页类将生成分页链接 您并计算偏移量和限制。这是 php 可重用的一个很好的例子 类,您可以在多个项目中使用它,而无需重写或更改它。

            $paginator = New Paginator($rows_found,8);
                $pagination_links = $paginator->get_pagination_links();
            
                $offset_and_limit =  $paginator->get_offset_and_limit();
            
                //apend the limit and offset to your sql query
                $query = $query. ' '.$offset_and_limit;
            
                $connection = getdbconnection();
                $stmt = $connection->prepare($query);
                $stmt->execute();
                $movies = $stmt->fetchAll();
            

            当然,本示例未涵盖 OOP 中的更高级概念,但这应该让您对类和对象的工作方式有一个基本的了解

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-11-26
              • 1970-01-01
              • 2012-05-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-10-12
              • 1970-01-01
              相关资源
              最近更新 更多