0

我项目中的所有代码都是程序性的。它没有使用任何框架或任何 MVC 结构。大多数 PHP 是带有一些逻辑的表单处理程序。很多这样的代码:

<?php

require "headerFile.php";

$user = array(); // filled with user data

if (isset($_POST['submitButton'])) {
    if (isset($_POST['money'])) {
        if (is_numeric($_POST['money'])) { // I don't actually validate numbers this way
            if ($_POST['money'] <= $user['money']) {
                $query = mysql_query("SELECT * FROM someTable WHERE id={$user['id']}");

                if($result = mysql_fetch_array($query)) {
                    if ($someOtherCheck == $user['someOtherData']) {
                        /*
                         * run some queries, give user some item
                         *
                         */
                    } else {
                        echo "This isn't right.";
                    }
                } else {
                    echo "You don't have a row in some table!";
                }
            } else {
                echo "You don't have that much money!";
            }
        } else {
            echo "Enter a valid number";
        }
    } else {
        echo "Enter how much you want to wager.";
    }
}

// some hard coded form goes here

require "footerFile.php";

?>

有一百多种这样的形式和嵌套的 if 处理程序,其中一些与更多/更少的条件相似。

我想开始使用 OOP,并且一直在阅读设计模式,但似乎找不到任何适用于我的项目的东西。

我正在添加与上面的代码块类似的大量新代码块,我不想复制和粘贴,只是在这里和那里更改一些位,我有什么选择?

4

7 回答 7

2

首先,如果您曾经复制和粘贴应该是BIG RED FLAG的代码。这应该是一个警告,您需要编写一个可以使用的通用函数,而不是复制和粘贴。

其次,是时候停止使用mysql_query-like 函数了。甚至PHP 页面也表示不鼓励使用这些函数。我将开始将您的 SQL 转移到更像 OO 的 PDO。

当我继承了一个看起来像您发布的代码的应用程序时,我写了一篇关于我开始处理事情所采取的步骤的博客文章。它也可能对您有帮助 - http://mattmccormick.ca/2011/10/13/how-to-refactor-a-php-application/

于 2012-10-02T22:23:17.657 回答
1

OOP 并不总是与应用程序有关。它是关于可读性和结构的。老实说,您在此处发布的代码的可读性如何?有很多事情正在发生,你需要 10 分钟才能把它们全部破译。但是,如果您将其分解为具有类函数的类,您将能够浏览事物并知道发生了什么。

OOP 并不总是为 php 做很多事情,但它是您想要为几乎所有其他非静态加载语言做的事情。另一个好处是,如果您在一个项目中拥有多个程序员,那么您都可以阅读代码。评论是你的朋友。

您最好的选择是使用带返回的函数。返回该值,然后该函数执行它需要做的任何事情。我个人会做类似的事情

$class->检查

如果错误

$this->error_handler

并且函数错误处理程序执行您希望它对错误执行的任何操作,如果它的死亡或回显然后执行此操作,但是您构建错误处理程序,因此如果您想要更改它,您可以将它放在一个地方而不是 20 .

于 2012-10-02T21:58:59.900 回答
1

即使不引入 OOP,您也可以为构建可读的代码创造奇迹。如果它们不相互依赖,则无需嵌套条件。

$form_is_valid = true;

if (!isset($_POST['submitButton'])) {
    echo "This isn't right.";
    $form_is_valid = false;
}

if (!isset($_POST['money'])) {
    echo "Enter how much you want to wager.";
    $form_is_valid = false;
} elseif (!is_numeric($_POST['money'])) {
    echo "Enter a valid number";
    $form_is_valid = false;
} elseif (!$_POST['money'] <= $user['money']) {
    echo "You don't have that much money!";
    $form_is_valid = false;
}

if ($form_is_valid) {
    do_stuff_here();
}
于 2012-10-02T22:12:34.377 回答
1

关于框架

一个体面的框架将帮助您通过关注点分离更好地组织代码,但不一定强制执行最佳实践。主观上,我说在最佳实践在您的脑海中根深蒂固之前,需要动手经验并犯很多错误。

尝试将框架仅视为一种交付机制。理想情况下,您的代码不依赖于任何一个框架。这通常意味着使用组件来处理应用程序的不同方面,例如路由、验证、配置、事件、依赖项等。


关于面向对象

我觉得你应该从SOLID 原则入手。这将帮助您,尽管不能保证,避免犯错误,从而花费您大量的时间。

首先,您的对象应该只有一个职责。例如,Product对象不应该负责充当数据存储、持久化自身、处理订单等。

另一个大问题是依赖注入。这对于单元测试你的类来说是巨大的(你应该养成这样做的习惯)。简而言之,不要类中构造依赖关系。预先构造它并通过构造函数参数或 setter 方法将其传递。

构建应用程序的过程值得拥有自己的书籍,所以我不打算在这里全部写完。但是,如果您遵循 SOLID 原则,那么您将在成为更好的开发人员的道路上取得成功。


关于你上面的代码

这种嵌套通常是一种气味,我明白你为什么要问这个问题......

第 1 步是将验证分离到它自己的服务中。至少在 MVC 意义上考虑这一点,您的控制器将只有 [pseudocode] if ($form->isValid()) { do something }。仅此一项就消除了您拥有的大量意大利面。

于 2012-10-02T22:24:36.970 回答
0

看起来您的代码正在组合模型层和视图层的某些组件。您正在对数据库运行查询,并且在同一个地方,您正在包含硬编码的表单。因此,一个不错的起点是将这些任务分成两个单独的类。例如,编写一个类来连接到您的数据库并对其运行查询,并编写另一个类来实际提供您的内容。

我对设计模式的建议是不要太拘泥于细节。相反,试着理解为什么某些模式如此有用,以及它们试图解决什么问题。很多初学者都陷入了“如何”的困境,当一个简单的解决方案就足够了时,他们最终浪费了很多时间来学习框架的细微差别。

最后,当你阅读你的代码时,留意那些可能被构造成一个类的东西。另外,请记住专业化是关键,通过构建非常专业的类,您正在构建可能用于其他项目的模块化组件,

于 2012-10-02T22:19:05.583 回答
0

我想开始使用 OOP,并且一直在阅读设计模式,但似乎找不到任何适用于我的项目的东西。

您还不必开始patterns..了解基础知识,您就可以从那里进步..

这是一个基本的例子

if (isset($_POST['submitButton'])) {

    $db = new \mysqli("localhost", "user", "pass", "db");

    $user = new User("Juddling Stack", 123456);
    $user->setMoney(500.01);

    $player = new PlayerRegister($db, $user);

    if (! isset($_POST['money']) || ! is_numeric($_POST['money']))
        $player->addError("Enter Valid Wager Money");

    if ($_POST['money'] <= $user['money']) {
        $player->addError("You don't have that much money!");
    }

    try {
        $player->doSQL();
    } catch ( BaseException $e ) {

        foreach ( $e->getError() as $error ) {
            echo $error, " <br />";
        }
    }
}

使用的类

于 2012-10-02T22:55:23.883 回答
0

让我们首先说明您遇到的问题不是使用 OOP,而是programming-overhead用程序员的术语称为 or spaghetti-code

如果您遇到很多开销,这意味着浪费时间编写几乎完全相同的代码行,其中只有内容不同,但功能相同。然后开始切割与其功能相同但内容不同的代码。

你说还有更多要复制粘贴,甚至更复杂,我只做form验证部分(我称之为阶段 1),这只是一个简单的例子,说明如何应用为你完成所有工作的逻辑提供它期望的输入。一个例子可能比其他例子更优雅。

以下所有代码均未经测试

定位具有相同功能的代码的示例。

 // functionality on checking values is the same, but it's content is not
 if (isset($_POST['submitButton'])) {
   if (isset($_POST['money'])) {
     if (is_numeric($_POST['money'])) {

 // though every decision made by its content is only being produced once .. 
      } else
          echo "You don't have that much money!";
    } else
        echo "Enter a valid number";
} else
    echo "Enter how much you want to wager.";

现在的诀窍是找到一个逻辑上解决这个问题的解决方案。PHP的内置函数很多,但首先要掌握如何解决它的想法。一个例子是让每个key,比如submitButtonmoney有一个等于not exists如果没有设置/存在的值,比方说null。其次,您正在将值与 提供的键进行比较$_POST,所以无论如何......您的$_POST数组是决策者。

可以看到一个关于如何使用将默认值应用于键jQuery的方法构建库的敏锐示例,因此键始终具有值并且始终通过不首先检查它是否存在来做出决定。$.extend()但是PHP也可以。

让我们默认值。

$_POST = array_merge(array(
  'submitButton' => null,
  'money' => 0,
  'etc' => '...'
, $_POST);

构建一个函数来验证这个数组现在容易多了,因为你总是可以依赖一个存在的值。

您说您有更多需要验证的表单,接下来要解决的是验证某些字段的功能。

有效无效形式的正式表示可以是数组,例如

$valid_form = array(
  'submitButton' => array('not_null'),
  'money' => array('not_null','int'),
  'etc' => '...'
); 

验证的功能是

function validateForm($values, $valid) {
  // error array to be returned
  $error = array();
  // let's iterate over each value, remember we defaulted the $_POST array with
  // all the fields it can have, so all fields should be iterated apon.
  foreach($values as $key => $value) {
    if(array_key_exist($key, $valid)) {
      // logic content can be used by different functions, switch
      // used here for simplicity
      foreach($valid[$key] as $validation) {
        switch($validation) {
          case 'not_null':
            if(is_null($value)) {
              $error[] = "error logic";
              continue; // skip rest
            }
          break;
          case 'etc':
            $error[] = "..";
          break;
        }
      }
    }
  }
  return $error ? $error : true; // true being valid
}

错误处理可以通过多种方式完成,仅举一个简单的示例(取决于该项目的广泛程度),您可以将错误内容绑定到验证键,例如

$vfe = $valid_form_errors = array( // $vfe for simlicity's sake
  '__no_error' => 'no error present for "%key%" validation',
  'not_null' => '%key% should not be null',
  'int' => '%key% expects to be an integer'
);

$valid_form = array(
  'submitButton' => array('not_null'),
  'money' => array('not_null','int'),
  'etc' => '...'
);

创建正式错误消息的函数

function error_msg($key, $validation) {
  global $vfe;
  // error exists?
  $eE = array_key_exists($validation,$vfe);
  return str_replace('%key%', $eE?$key:$validation, $vfe[$eE?$validation:'__no_error']);
}

而在简单的开关中,错误逻辑是

  foreach($valid[$key] as $validation) {
    switch($validation) {
      case 'not_null':
        if(is_null($value))
          $error[] = error_msg($key, $validation);
      break;
      case 'etc':
        $error[] = "..";
      break;
    }
  }

那么你的代码使用不同的逻辑会是什么样子呢?

    // first stage ..
    $form_valid = validateForm($_POST, $valid_form);    
    if ($form_valid === true) {
      // second stage, same logic be applied as with validateForm, etc.
      if($_POST['money'] <= $user['money']) {
        $query = mysql_query("SELECT * FROM someTable WHERE id={$user['id']}");

        if($result = mysql_fetch_array($query)) {
            // third stage, same logic can be applied here..
            if ($someOtherCheck == $user['someOtherData']) {

            } else {
                echo "This isn't right.";
            }
        } else {
            echo "You don't have a row in some table!";
        }
    }
    else {
      $errors = $form_valid;
      // error handling here
      print_r($errors);
    }    

这一切都取决于您可以定义预期值的具体程度。您可以将每个功能扩展为更具体,例如将错误绑定到表单键,以便您可以在稍后阶段专门针对该输入。他们的关键是消除所有可能的重复,一个函数可能会为你做这一切,只需让他比较你期望的值,让他告诉他实际上有哪个值。

于 2012-10-02T23:08:57.463 回答