PHP:真实世界的OOP示例

时间:2009-08-27 20:37:18

标签: php oop

我正在努力学习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的真实示例?

8 个答案:

答案 0 :(得分:80)

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

答案 1 :(得分:9)

购买“PHP和Mysql日常应用程序傻瓜”这样的书。

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

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

OOP非常类似于将程序的各个部分分组为可重复使用的部分。与你说实话并不难,只是将你的功能打包成课程的想法。

以下OOP内容的真实世界迷你示例:

CLASS DATABASE
课堂会议
CLASS WEBFORMS
CLASS EMAIL

CLASS ACCOUNTS(以下示例功能)
功能选择帐户
功能检查密码

功能CHECKUSERNAME
功能创建账号

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

祝你好运!

答案 2 :(得分:2)

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

我不相信你应该使用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文件,该文件将向您展示如何使用composer包。例如https://github.com/moltin/laravel-cart是您可以在应用程序中使用的购物车包的示例。请注意您不需要查看包源代码以了解包的功能。这个软件包已经编写好了,你不关心它们是如何工作的,但你使用它们只需要知道如何使用它们。这正是OOP的意思。

  

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

您正在做的是深入了解源代码,作为了解OOP如何工作的工具。

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

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

我认为您应该尝试在本地计算机上安装Laravel Framework或其他“体面的现代框架”。为什么我说现代,因为现代框架需要一个5.3+的最小PHP版本,这意味着你的机器上的PHP将支持类似于你从Java那样的实际OOP。

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

如果要与数据库进行交互,最初将在控制器方法中创建一个new Model对象。当您开始学习更多内容时,您将开始学习如何将依赖项注入控制器,然后学习如何转储模型并创建存储库并编程到接口。

一本关于为初学者学习Laravel的好书将由Dale Rees https://leanpub.com/codebright。两周前我在Laravel聚会上遇见了Dale。

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

  • 单一责任原则
  • 开放封闭原则
  • Liskov替代原则
  • 界面分离原则
  • 依赖性倒置原则

答案 3 :(得分:1)

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

尽管如此,我认为从大量的生产代码中学习并不容易,因为它并没有真正教会你什么。但是如果你想要真实的面向对象的PHP代码,那么Zend Framework(或Symfony,或者也许是CakePHP)可能就是这样。

答案 4 :(得分:1)

我建议你暂时远离任何框架,如果你不了解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。

答案 5 :(得分:1)

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

Here指向PHP和Mysql日常应用程序傻瓜书的链接

答案 6 :(得分:0)

我建议也看看我的包装Arrayzy。它是OOP方式的本机PHP数组易操作库。

因此,如果您使用本机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问题,了解更多详细信息,以及它的缺点和道具。

答案 7 :(得分:0)

您说得对,您可以在网上找到 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 中有更高级的概念没有在这个例子中介绍,但这应该能让你对类和对象的工作方式有一个基本的了解