选择在php OOP设计中使用哪些类

Dan*_*Dan 7 php oop procedural performance

我经营一个街机网站,在过去的几年里,它增加了许多功能,它已经到了程序编程看起来太复杂的地步,添加新功能或进行简单的设计修改可能非常棘手.

因此,我决定尝试使用相同的功能从头开始重新编码网站,但是采用OOP格式.

我遇到的问题是选择课程,我理解OOP以及它应该如何工作但似乎总是难以入门.我不确定是否应该尝试为具有登录用户功能的用户类等类创建函数,或者如果用户类应该只是添加/更新/显示用户详细信息,并且系统中的登录部分会更好类?

目前我已经开始使用以下类和函数,但它们是否适合此类别?

<?
class User {

    var $userId,
        $username,
        $userRole,
        $userEmail;

    function isLoggedIn(){

    }

    function login($postusername, $postpassword)
    {

    }

    function increaseLoginCount(){

    }

    function logout(){

    }
}
?>
Run Code Online (Sandbox Code Playgroud)

然后我可以在page.php中使用类似下面的内容..(连接类未显示)

<?
$db = new Connect;
$db->connect();

$user = new User;

if(!$user->isLoggedIn())
{
    echo "Please Log In.";

    if($_POST['user'])
    {
        $user->login($_POST['username'], $_POST['password']);
    }
}
else
{
    if($_POST['logout'])
    {
        $user->logout();
        exit;   
    }

    echo $user->username." Logged In.<br />";
}
?>
Run Code Online (Sandbox Code Playgroud)

但是,该网站将有页面显示游戏类别,我不知道displayGames()函数适合哪里,因为它不是一个游戏,所以不会进入'游戏'类?

我试图找到'真实世界'的例子,但PHP代码告诉我如何使大象改变颜色或舞蹈并没有真正帮助...

hak*_*kre 9

让我们从一些文本分析开始,由我强调:

我运行一个商场的网站,并过去的几年中

想想能够应付多少以及你正在处理什么.还要了解多年来您已经获得了有关运行街机网站的具体知识.您已获得所在地区的专业.永远不要低估自己的地位和资产,这是你经营的基础,你将引入变革.这包括您网站的用户群.

它增加了许多功能,它已经达到了程序编程看起来过于复杂的程度,添加新功能或进行简单的设计修改可能非常棘手.

如果系统增长,它们会变得越来越复杂.这不仅仅是程序式编程,而是事实.当您现在运行该网站多年时,您就会知道事情的变化,特别是在用户与您网站的接口方面.

所以我决定尝试,并从地上爬起来重新编写网站相同的功能,但在一个面向对象的格式.

据说可以使用OOP技术制作可重复使用的软件,有(并且不能)任何证据.

但是商业软件开发中只有很少的例子,从头开始重写整个应用程序是成功的.很少.商业软件开发规则可能不适用于您的具体情况,所以只是说.

在重新编码站点之前请三思.做很多工作只是为了达到同样的目标,这有点徒劳无功,令人失望.相反,可能更具体地看一下你当前的设计中哪一个引入了你想要改变的最大问题.

这是可能的PHP混合程序和面向对象的风格,当你拥有它可以是特别有用的遗留代码(一个公认的定义遗留代码是代码W/O自动化测试).

我的问题是选择课程,

我试着改写一下:为什么写类?

理解OOP以及它应该如何工作但似乎总是难以入门.

开始始终是最艰难的一步.你现在已准备好做出决定,但你无法展望未来.消除风险最大的部分,降低风险.你可能已经开始在这里提出一个问题,以获得一些反馈来作出决定,但这可能不会减轻负担并可能导致混淆.然而,接受教育往往是一件好事.

我不确定是否应该尝试为具有登录用户功能的用户类等类创建函数,或者如果用户类应该只是添加/更新/显示用户详细信息,并且系统中的登录部分会更好类?

这在很大程度上取决于应用程序的性质和用户的性质.可能大多数脚本只需要知道用户是具体的还是匿名的(匿名用户还没有登录),它的ID,名称或昵称.

应用程序应该将该用户提供给任何消费组件,因此每个命令/脚本不需要处理:a)获取用户信息和处理用户(如登录),b)验证组件是否对用户有效(访问控制) ).这应该放在别的地方,例如在应用程序控制器PofEAA.

每个具有应用程序控制器对象的脚本/命令都可以请求用户并与用户进行交互.

然而,这只是从技术上讲.处理自己不确定的事实,处理这些信息.尝试更好地制定具体问题,列出解决问题的具体方法的优缺点,在开始编码之前再次远离具体代码.然后比较利弊.尽量使事情变得更简单,更简单.

可能用简单的文字写下应该发生什么而不是编写代码.

目前我已经开始使用以下类和功能,但它们是否属于这一类**?**

你的代码非常简陋,所以很难说出来 - 特别是因为我不知道你的街机网站是什么(以及你所写的类别).它可能仍然适用于一个例子.在您的课程中可以看到的是,您将所有内容紧密地整合在一起.

例如,您从数据库开始.这很常见,因为DB是任何应用程序的核心组件.应用程序需要DB才能运行.但是,您希望保持松散耦合,以便所有命令都可以与其他数据库或新应用程序对象一起运行,该用户对象与某些应用程序的数据对象之外的其他数据库连接.

 $application->getDB();
Run Code Online (Sandbox Code Playgroud)

由于用户是每个应用程序中的中心主题,因此它应该具有非常简单的界面.有关身份验证,检索用户属性等的所有荣耀细节都应该委托给另一个类/组件,以便您可以更改存储用户的实现以及它们如何进行身份验证:

 /**
  * @package command.modules.games
  */
 function ListGamesCommand(Request $request, Response $response)
 {
     $application = $request->getApplication();
     $user = $application->getSession()->getUser();
     $games = $application->getModels()->build('games');
     $games = $games->findByUser($user);
     $response->setProp('games', $games);
 }
Run Code Online (Sandbox Code Playgroud)

如此示例所示,您可以在需要时添加功能.例如,只要您的应用程序不需要实际登录用户,为什么要关心它现在的编写方式?

创建一个为应用程序对象生成用户的工厂 - 无论现在还是将来需要它(参见清洁代码会话两堆对象- 继承,多态和测试).如果您需要身份验证,请将其添加到会话对象或用户对象界面.

无论如何,身份验证本身都会在它自己的类中实现Authenticator.因此,您可以稍后通过将身份验证调用从会话移动到用户或其他任何内容来查看您的接口.只有一小部分命令需要处理这些特定任务,并且由于所有新代码都在自动测试中,因为您希望重写并从OOP中受益,因此您已确保所有位置都被覆盖并正确地重新计算.

访问请求变量也是如此.如果你想利用OOP的好处 - 它与间接高度相关(并且每个间接层都需要付出代价) - 首先应该让你的基类对特定数据进行操作而不是对任何数据进行操作(如全局和超全局,我$_POST在你的示例代码中看到过).

因此,启用新代码以处理请求并提供响应(输入 - 处理 - 输出):

$request  = new Request($_SERVER, $_GET, $_POST, $_COOKIE, $_FILES, $_ENV);
$response = new Response;
Run Code Online (Sandbox Code Playgroud)

BankAccount获取的示例 - 用于PHPUnit培训的示例应用程序

现在,这下面的所有内容都可以在一个Request和一个Response对象上运行 - 处理输入并将其转换为输出.该domain命令(脚本/该做的事命令)并不需要关心的任何时间的约从HTTP请求喜欢使用提取的输入$_POST或者$_GET他们可以采取直接从Request-或者,如果你写一个类它自己的命令-这可以更加量身定制.并且一些命令可以对它们自己的请求和响应进行操作.

下一个重要主题是用户界面.你写的你想要:

我决定尝试使用相同的功能从头开始重新编码网站,但是采用OOP格式.

我已经写过,这样做可能毫无结果.获得OOP代码的好处意味着下次更改代码时,您仍然可以重用组件.随着软件不断变化,现在这一次已经是下一次了.所以你想要重新使用现有的代码.我假设您现有代码的一部分是输出逻辑.因此,现有的输出逻辑需要与示例性RequestResponse上述接口连接.

我打赌你喜欢网站.你喜欢让它们工作,看起来很棒.多年来你已经建立了自己的网站,即使并非一切都像你希望的那样,你也不想放弃它.因此,对于重写而言,重要的是你不要破坏所有东西,但是从现在到将来你可以保留它的工作形式(参见保留工作应用程序 ;列表的最后一点).

在webapps中,视图是至关重要的部分.如果您放弃了视图,您的网站将失去其身份.如果您对其进行了大量更改,您的网站将会让那些对今天使用它感到满意的用户感到失望.

如果你打破它,

  1. 你会注意到吗?
  2. 你能修好它吗?

另一方面,您希望您的应用程序代码(功能,功能)不再与它紧密绑定,以便在重写代码时获益.当你想重写你的应用程序时,让我们来看看:

     .---------.                            .-------------.
     | website |  ---> [interface in ] ---> | application |
     | user    |  <--- [interface out] <--- |             |
     `---------´                            `-------------´
Run Code Online (Sandbox Code Playgroud)

如此架构所示,为了使您的应用程序更加独立于交互的外观(可以是网站,(智能手机)GUI或票务系统),应用程序代码应该是可替换的.您不希望编写逻辑来获取用户游戏,例如新应用程序代码中的每种类型的用户界面,但您在旧的应用程序代码中进行了操作.

User以此为例,以此为例.它如何进行身份验证以及存储位置不应该是您的新应用程序命令代码所关注的内容.如果命令需要它就在那里.不是全局的,而是具体的,如果命令要求它.

其中 - 注册和丢失密码程序是您现有应用程序的一部分并继续存在.

现在您需要将旧代码和新代码放在一起.

因此,您可能会从HTTP请求和HTTP响应的接口开始.该视图启动了Interface Out.您通过该接口为视图分配/传递所有需要的数据,您的应用程序不再知道视图.您不需要处理新应用程序代码中的任何CSS,Javascript或HTML代码.这只是产量最高的糖.您的应用程序也应通过纯文本控制台/ telnet或远程XMLRPC服务,AJAX端点 - 无论如何接口.

所以你可以概括一下你的视图代码并为它注入变量.编写视图层可以像包含PHP文件一样简单.它对可在其范围内可用的变量进行操作.它可以使用其范围内可用的"辅助"函数(模板宏).它可以使用视图模型对象.甚至可以为视图编写自己的语言(模板语言,域特定语言(DSL)).

但是,只有在创建允许应用程序代码执行此操作的接口时,才有可能实现此目的.

所以你现在要做的就是将你的应用程序中的HTTP/HTML/CSS/JS移到它自己的适配器上.该适配器能够制定通用命令,该命令可以通过接口传递给任何应用程序.

应用程序只会注意执行命令并通过接口输出它的响应.所以你现在有两个域:你的应用程序和网站.

您可以开始创建这两个新域,然后为遗留代码提供接口,为新代码提供接口.

您还有"两个"应用程序彼此相邻.它们最终与您的数据库绑定在一起(在自己的代码中不可见),这会照顾您站点的数据.这就是数据库的用途.将数据与代码分开,以便随时更改代码.

此外,如果要重新编码,请在现有代码和新代码之间绘制边框.

祝好运!我希望阅读本文将为您的具体案例提供一些选择.另请注意,您不要将控制器转换为数据库的另一个外观.通过使用轻量级HTTP抽象和视图层,您可能获得了最好的好处(不知道具体的最大问题),因为您的应用程序可能仅适用于网站.

因为在HTTP/PHP中:

[Interface In]  Plain Text HTTP request
[Application]   Free to go
[Interface Out] Plain Text HTTP response
Run Code Online (Sandbox Code Playgroud)

您通常只需要一些功能来解析输入并构建输出.

另外,不使用胖模型的好处是可以快速顺序地访问数据,例如,如果您不需要立即传递输出(缓冲,一个块),您可以获得将输出流式传输到服务器.

您应该确定哪些部分对于您的应用重构是重要的,而不是OOP.与程序一样,OOP也需要做得好.如果您今天通过编写过程代码遇到问题,OOP代码可能无法解决您的问题.编写更好的程序代码的需要可能就是它.只是说,重构一个应用程序并不容易,你应该首先确定实际问题.

  1. 如果你打破它,你会注意到吗?
  2. 如果你打破它,你能解决它吗?

关键部分是您可以注意到并且您手头有一切可以修复.

让您的网站受到测试,这样您就可以说在这里或那里更改代码实际上是否有效.能够将任何变化都改回来,如果它发光它不起作用(更好).

这样做可以轻松决定是否有新功能.只要您不需要引入新功能,就无需更改编写功能的方式.在此之前,您无法计划新功能.

因此,在重新编写应用程序之前,最好三思而行.如上所述,这可能会导致项目失败.


请参阅: 如何在我的PHP/SQL/HTML/CSS代码上实现MVC样式?所以Q&A


Gor*_*onM 7

OOP旨在确定责任区域并构建旨在处理这些区域中的一个且仅一个区域的自包含代码单元.一般的经验法则是,系统中的每个对象都应该在现实世界中体现一个等价的对象或概念,但这并不总是正确的,因为您还需要担心使系统工作所需的抽象事物(我的意思是这里抽象)从某种意义上说,它们不代表业务逻辑的一个项目,但仍然需要使系统工作.我不是指抽象类,这是完全不同的东西).

例如,在您的游戏网站中,您可能需要处理游戏,用户,版主,帐户,评论,评论等.这些中的每一个都应该是一个类本身,并且该类的每个实例都应该代表特定的User,Game,Comment等.

但课程有责任范围,如上所述,课程应该处理其责任范围而不是其他任何问题.渲染页面不是上述任何对象类的责任.这是不代表系统实体的类的用武之地.你可能需要一个用于页面的类,一个用于Session的类,一个用于数据库连接的类(尽管PHP已经在那里介绍了PDO和一些其他数据库模块,如mysqli).

要呈现页面,您需要使用页面类的实例.您将传递给已登录用户对象的引用,对您希望它显示的任何游戏对象的引用,等等.然后你就可以渲染实际的HTML了.Page类不需要知道关于传递它的对象的内部工作原理,除了这些对象公开的API(在OOP圈中称为对象的协议,换言之,它们的公共方法和属性).(非常基本的)Page类可能如下所示:

class Page
{
    private $user = NULL;
    private $games = array ();

    public function setUser (User $user)
    {
        $this -> user = $user;
    }

    public function getUser ()
    {
        return ($this -> user);
    }

    public function addGame (Game $game)
    {
        $this -> games [] = $game;
    }

    public function getGames ()
    {
        return ($this -> games);
    }

    public function generate ()
    {
        $user = $this -> getUser ();
        $games = $this -> getGames ();

        $pageFile = '/path/to/a/php/script/representing/the/page/markup.php';
        require ($pageFile);
    }

    public function __construct (User $user, array $games)
    {
        $this -> setUser ($user);
        foreach ($games as $game)
        {
            $this -> addGame ($game);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

实际的markup.php脚本可能看起来像这样:

<html>
    <head>
        <title>Games page for <?php echo ($this -> user -> getName ()); ?>
    </head>
    <body>
    <p>Hello, <?php echo ($this -> user -> getName ()), here are your games.</p>
    <?php if (count ($this -> games)) { ?>
    <ul>
        <?php foreach ($this -> games as $game) { ?>
        <li><?php echo ($game -> getName ()); ?>: your best score is <?php echo ($game -> getHighScore ($this -> user)); ?></li>
        <?php } ?>
    </ul>
    <?php } ?>
    </body>
</html>
Run Code Online (Sandbox Code Playgroud)

您可能已经注意到,如果您使用此方法,那么您的应用程序的模块将倾向于属于三个类别之一.您的业​​务逻辑对象,如用户和游戏,您的显示逻辑,如markup.php文件,第三组,作为胶合逻辑和协调的形式,如Page类.

虽然在这种特殊情况下它是特定于您的站点,但如果您进一步概括这种方法,它将属于称为MVC的设计模式,其代表模型,视图,控制器(实际上它更接近于用于演示的PAC模式) ,抽象,控制器,但由于某种原因它几乎总是在PHP社区中称为MVC,所以我们现在只说MVC).模式是程序员经常遇到的一类问题的概括,具有预制解决方案的工具包是很方便的.

对于您的游戏应用程序,用户和游戏是模型,Page是控制器,markup.php是视图.如果将不同的markup.php脚本替换为此代码,则可以使用它以完全不同的方式呈现完全相同的数据,例如,作为XML文件.您也可以使用具有不同控制器的相同模型来使它们执行不同的操作.这里要记住的重要一点是模型不应该关注它们的使用方式,这样它们可以根据控制器需要实现的方式以不同的方式使用.

由于MVC是一种模式,因此已经存在用于构建MVC的工具包(尽管它们不是真正的MVC;)PHP中的应用程序.这些被称为框架.有很多可供选择,例如Symfony,CodeIgnitor,Zend Framework等.如今最受欢迎的框架是Zend,尽管我个人并不喜欢它.(我想说Zend Framework 2的测试版看起来确实比当前版本的框架好很多).

我希望这对你有所帮助.我知道OOP起初可能令人生畏.它确实需要你改变你作为程序员的思维方式,但不要担心,它会带来足够的练习.