开发强大的应用程序

4
我注意到有一些函数,比如is_int()isset()file_exists()functions_exists()是非常有用的。当我写代码时,总是会考虑到可能发生的任何问题,但有时候我会遇到一些问题,比如:

等等,这个变量是在PHP文件内设置的;这意味着没有人可以编辑它,对吧?如果这个“用户”可以编辑它,那么我将面临更多的麻烦,因为它将能够管理PHP文件。

或者

检查应该始终存在的文件是否真的值得这样做吗?

让我们考虑以下没有意义的示例,但这将帮助我让你明白我在说什么。 PS: 我故意夸大了代码。 config.php
$doActions = true;

functions.php

function getID() {
    return $_COOKIE['userid'];
}

class eye {
    public static function see() {
        // gain the object the user is looking at
        return $object;
    }
}

index.php

class viewer {

    private $poniesSeen = 0;

    public function __construct() {
        /* Magic ponies are created here */
    }

    public function sawAPony($id) {
        if (file_exists('config.php')) {
            if (isset($doActions)) {
                if (is_bool($doActions)) {
                    if ($doActions) {
                        if (file_exists('functions.php')) {
                            if (function_exists('getID')) {
                                $id = getID();
                                if (!empty($id)) {
                                    if (!is_int($id)) {
                                        settype($id, 'int');
                                    }

                                    if (class_exists('eye')) {
                                        if (method_exists('eye', 'see')) {
                                            $o = eye::see();
                                            if (is_string($o)) {
                                                if ($o = 'pony') {
                                                    if (isset($this->poniesSeen) and is_int($this->poniesSeen)) {
                                                        ++$this->poniesSeen;
                                                        return true;
                                                    } else {
                                                        return false;
                                                    }
                                                } else {
                                                    return false;
                                                }
                                            } else {
                                                return false;
                                            }
                                        } else {
                                            return false;
                                        }
                                    } else {
                                        return false;
                                    }
                                } else {
                                    return false;
                                }
                            } else {
                                return false;
                            }
                        } else {
                            return false;
                        }
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
}

现在,我认为应该保留哪些条件,而哪些条件应该被舍弃,因为它们根本没有意义?我为什么不应该检查它们,为什么应该检查它们?这种固执的行为是否有一个黄金法则呢?


11
我想我刚才噎住了。 - BoltClock
2
离题提示:考虑使用守卫条款:http://www.refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html - SebastianK
9个回答

6
这就是为什么语言通常带有错误信息的原因。如果出现问题,它不会默默地崩溃,而会告诉你。这样,您可以对您认为始终正确的内容做出合理的假设,如果因某种原因它不正确,您将得到通知。
以下检查是无用的,在我看来:
1. file_exists - 如果文件名已知并放置在那里,则可以使用此函数。如果参数是变量,则也可以使用该函数。 2. is_bool、is_int等-如果您坚持类型正确,则应使用===进行比较。我只使用了其中的一个:is_array。 3. function_exists和类似功能-如果您知道文件在那里,并且您将函数放入文件中,则可以安全地假定该函数存在。同样,有特殊情况下此函数很有用,但您的情况不是其中之一。
isset在某些情况下可能很有用,例如检查数组是否包含给定键的非空值,或者是否在$_REQUEST中传递了参数。还有其他检查方法不涉及isset,但这不是我的重点。
如果您可以合理地期望您断言始终正确,即发生数据损坏或您的巨大错误才会使其变false,请勿检查。如果在100万次尝试中出现错误,那么您可以捕获错误并为下一次修复它。否则,您的代码可读性成本太大。

不错的回答。file_exists 可以用于检查动态创建的文件,例如缓存文件。is_numeric() 也是一个很方便的函数,同时使用 === 运算符而不是 == 运算符更好,因为它具有类型明确性。 - Lawrence Cherone
错误信息对于开发人员来说是一个好的参考点。然而,当开发带有某种UI的东西时,为用户明确解释事情总是很好的,因为他们可能无法看到或理解标准的错误输出。 - celem
@Lawrence 你说的 is_numeric 是对的。但我不认为它属于那些函数之一。“numeric” 不是一种类型。尽管如此,它对于输入检查非常有用。 - Tesserex
@celem 是的,但是UI错误和开发错误是两个不同的问题。他所说的检查是为了防止编码错误。有用的错误信息和输入检查是为了防止和处理用户错误。任何用户都不应该看到关于函数不存在的消息。 - Tesserex

4

通常我很少使用这些类型的检查,显然是为了避免产生像上面那样的代码。

例如。

不要检查您自己创建的文件是否存在。检查用户文件的存在,您可能正在尝试从中进行写入或读取。

当涉及到类型检查时,同样不要检查不会更改的东西的类型。确保对来自诸如表单元素之类的用户输入进行类型检查。如果函数需要一个整数,则检查它是否获取了一个....如果有可能没有获取到(用户写了他的名字或其他内容)


2
这完全取决于您的应用程序。
这样做毫无意义:
$foo = 3;
if (is_int($foo) && $foo > 3)
  // ...

然而,任何来自外部来源的内容都应该经过仔细检查。即使它来自数据库,在那里你认为所有数据都是安全的,也要深思熟虑是否可能出现问题。
因此,并不总是需要检查。花一点时间思考是否需要进行检查是明智的。
但有一个黄金法则:任何可能出错的事情,最终都会出错

1
如果你确实需要进行大量的检查,可以像这样反转检查并在失败时立即返回:

public function sawAPony($id) {
  if (!file_exists('config.php')) {
    return false;
  }

  if (!isset($doActions)) {
    return false;
  }

  // etc
}

这样你就可以避免过多的缩进和试图匹配大括号。但是理想情况下,你可能需要找到一种方法来重构所有的检查。

我认为,用&&将它们全部连接起来并不会使代码更易读。

至于需要检查哪些内容 - 你应该检查任何你的代码所依赖的东西,前提是这些东西不被你运行的系统保证。

总是检查那些你无法控制的事物(尤其是用户输入、外部服务等)。如果你发现自己在很多地方都添加了这些检查,请将它们重构到某个地方。


1

这是一个与PHP设计/编程风格相关的问题。许多Web程序员喜欢使用可能已经声明并分配了初始值的变量(我想称之为“动态类型”)。

而这些变量可以是任何类型,或者很容易从一个类型转换为另一个类型(例如从“字符串”到“整数”)。 PHP和其他Web编程语言都允许这样做。

当我编写自己的PHP文件时,我通常像编写静态类型语言一样编码:


mylibrary.php

// expects a 0 | 1 (boolean) query-string parameter, even if not present ?
// "pseudo-declare it"

/* bool var */ $myOption = false;
$temp = $_REQUEST['option'] ;
if ($temp != NULL) {
  $myoption = ((int)temp == 1);
}

/* int */ function myFunction () {
  // simulate variable declarations,
  // and initial values, like other languages
  /* int var */ $result = -1;

  global /* bool var */ $myOption;

  /* bool var */ $doSomething = false;

  while (...) {
    ...
    if ($myOption) {
      $doSomething = true;
    }
    ...
  }

  return $result;
}

这种冗长的编码方式,让我能够避免所有这些存在或类型检查函数。


1

Charlie,

你所做的是非常冗余和不必要的。PHP已经为你处理了大部分的东西(例如:确保字符串中的数字被解释为整数,然后在变量在两行之间没有使用时稍后检查它是否为int),这些都是不必要的。

这就像穿着全套太空服坐在防弹车里开车,离任何可能撞到的物体10英里远一样。

如果你的代码不仅仅是一个例子,而且有实际用途或者有意义,我可以为你重写它,告诉你应该采取正确的“安全措施”,但我还是会尝试一下。

include("config.php"); 
include("functions.php");
class viewer {
private $poniesSeen = 0;
public function __construct() { /* 魔法小马在这里被创建 */ }
public function sawAPony($id) { $object = eye:see(); if($object == 'pony') { $poniesSeen++; return true; } return false; } }

哈哈,我认为这就是了。已经足够好了。关注你的程序逻辑,而不是程序的程序(如果有任何意义的话,可能并没有)。

干杯!


0
首先,在任何小型项目中,我们都无法摆脱条件检查。如果您需要进行大量检查,请先将它们全部清晰地编写出来。然后根据可以一起检查的条件考虑重构代码,例如:
if(a!=0){
   if(b!=0){
      // do this
   }

可以重写为

if(a!=0 && b!=0) {
   //do this
}

(为了简单起见,我把它做得太简单了。)

0

我没有完全检查你的代码。但是为了回答你的问题,如果你对变量有完全控制权,除了你以外没有其他人在你的系统上工作,并且它不接受任何外部用户输入,你可以考虑跳过这些检查。

但编程的整个问题在于我们永远无法确定我们的应用程序将经历什么。

一个经验法则是,如果您期望您的应用程序在未经审查的情况下失败,则应进行检查。你不觉得这值得吗?

确实,PHP文件中创建的变量不受用户控制。但是,如果涉及到用户输入并在其他地方传递到您的方法中,那么2或3级别之后呢?这就是为什么最好验证、类型检查并为所有变量分配默认值的原因。

最终,安全起见还是比较好的。


0

:-D

首先,要注意一些可能会对您的应用程序造成重大问题的事情(例如需要删除类的旧文件版本)。如果发生这样的情况,只需向用户呈现一个漂亮(或有用或两者兼备)的500页,并进行警报。否则,您可能会在稍后的某个地方崩溃,这将更难调试。

  • file_exists可以被require "file"替换
  • class|method|function_exists可以省略,如果您不能没有它们并且您希望它们存在

如果您期望在代码中设置了某些变量(只需在开发环境中打开通知),则再次不需要isset

当处理输入时(例如当您期望数字时),更改数据类型非常有用。

所有这些都假定您对正在执行的代码具有良好的控制。如果某人不受信任的人可以修改您代码的某个部分,那么祝你好运。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接