AntiPHPatterns和AntiPHPractices

AntiPHPatterns

反PHP模式

Design Patterns are independent solutions to problems that occur over and over again.  Usually these are considered at a high level without much detail.  They are independent of core-implementation things like the exact language or data base.  And at the opposite end of things we find AntiPatterns which appear to be solutions, but are actually counterproductive, ineffective or subtly dangerous.  In 2010 Stefan Priebsch coined the phrase AntiPHPatterns, to describe some of these high-level pseudo-solutions that appear in PHP.  His excellent description was presented in London at the UK PHP conference.  His collection fell into four general categories: Constantitis, Globalomania, Singletonitis, and Godclass.

设计模式是针对反复出现的问题的独立解决方案。 通常,在没有太多细节的情况下从较高的角度考虑这些内容。 它们独立于诸如核心语言或数据库之类的核心实现事物。 相反,我们发现反模式似乎是解决方案,但实际上适得其反,无效或微妙的危险。 2010年, Stefan Priebsch创造了短语AntiPHPatterns ,以描述出现在PHP中的一些高级伪解决方案。 他的出色描述在伦敦英国PHP会议上发表。 他的收藏分为四大类:君士坦丁炎,全球性狂躁症,单胎炎和Godclass。

In this article I'll touch on Stefan's excellent analysis, and then I will add a collection of my own AntiPHP examples, showing how novice programmers often over-think or under-think specific problems.  I have seen these things in my work over the years, and on the occasions when I have had the opportunity to refactor, the view in hindsight has helped me to understand why some newer ways of looking at problems can help create a library of effective teaching examples.

在本文中,我将介绍Stefan的出色分析,然后将添加我自己的AntiPHP示例的集合,以显示新手程序员如何经常对特定问题进行过度思考或不足。 这些年来,我在工作中已经看到了这些东西,而当我有机会进行重构时 ,事后的观点帮助我理解了为什么一些新的解决问题的方式可以帮助建立有效的教学库例子。

Constantitis

恒炎

In PHP, the define() function creates a constant.  Constants are immutable and global, and they can be defined anywhere in the code base.  As a result, it is entirely possible that two programmers working on the same project may define a constant with the same name, thus causing a collision that results in a run-time failure.  The presence of many global constants is a code smell.  Among other things, it may imply a large measure of configuration over convention, and with many possible configurations, things can become confusing.  In addition, if you want to change the settings that depend on the constants, you have to change the constants in the script.  Yecch!

在PHP中,define()函数创建一个常量。 常量是不可变的且是全局的,可以在代码库中的任何位置定义它们。 结果,在同一个项目上工作的两个程序员完全有可能用相同的名称定义一个常量,从而导致冲突,从而导致运行时失败。 许多全局常量的存在是代码的味道 。 除其他外,这可能意味着对约定的大量配置,并且对于许多可能的配置,情况可能会变得混乱。 另外,如果要更改依赖于常量的设置,则必须在脚本中更改常量。 是的!

Globalomania

全球狂

In PHP, the global keyword creates a global variable, one that appears suddenly and unexpectedly in every namespace and scope.  This is slightly worse than a global constant, since it can be changed, and a change in one area of the script may have unwanted effects in other areas of the script.

在PHP中,global关键字创建一个全局变量,该变量在每个命名空间和作用域中突然且意外地出现。 这比全局常量稍差一点,因为它可以更改,并且脚本一个区域的更改可能在脚本的其他区域产生不良影响。

Singletonitis

单疱炎

The singleton design pattern tries to solve the problem of having multiple instances of the same class, when only one instance is needed (eg: a data base connection).  But in practice, singletons are often used as if they were global variable containers. Singletons may share same the code smell with other globals (constants and variables).  Singletonitis has the same cure as constantitis and globalomania, which is dependency injection.

单例设计模式试图解决只需要一个实例(例如:数据库连接)时具有同一类的多个实例的问题。 但是实际上,单例通常被当作全局变量容器使用。 单例可能与其他全局变量(常量和变量)共享相同的代码味道。 单纯性疱疹的治疗方法与常量性炎和全身性肥胖症相同,即依赖注射

Godclass

神级

It is axiomatic in software development that encapsulation is good, both for code and data.  A well-written class should do one thing perfectly (or as close to perfectly as possible).  If you try to describe the purpose of a class and you use any conjunctions, your class is probably defective because it is doing too much work in too many different ways.  When you find that an entire web page can be rendered by calling upon a single class, you've found Godclass.  The couplings and dependencies of the classes that extend Godclass are not readily visible, making it hard to know what changes will have adverse effects.  The cure for Godclass is isolation of data and functionality, so that objects know "all about" themselves, but treat other objects as if they are "black box" vending machines.  In other words, "minimize class responsibilities."

在软件开发中,对代码和数据的封装都很好,这是公理的。 编写良好的课程应该完美地完成一件事(或者尽可能接近完美)。 如果您尝试描述类的目的并且使用任何连接词,则您的类可能是有缺陷的,因为它以太多不同的方式进行了过多的工作。 当您发现可以通过调用单个类来呈现整个网页时,您便找到了Godclass。 扩展Godclass的类的耦合和依存关系不容易看到,这使得很难知道哪些更改将产生不利影响。 Godclass的解决方法是隔离数据和功能,以使对象了解自己的全部知识,而将其他对象视为“黑匣子”自动售货机。 换句话说,“最小化班级责任”。

So much for antiPHPatterns.  Now let's look at AntiPHPractices.

对于antiPHPatterns来说,太多了​​。 现在让我们看一下AntiPHPractices。

AntiPHPractices

反PHP实践

AntiPatterns are the high-level concepts gone awry.  More plentiful and finer grained blunders and code smells are called AntiPractices.  If it seems like this article has a negative, "don't do that" tone, it's because the article is intended to steer you away from risky or dangerous practices!  If you find these things in your own programming, get rid of them as soon as you get a chance.

AntiPatterns是出问题的高级概念。 更丰富,更细粒度的错误和代码气味被称为AntiPractices。 如果这篇文章似乎带有负面的“不要那样做”的语调,那是因为该文章旨在引导您远离危险或危险的做法! 如果您在自己的编程中找到了这些东西,请尽快消除它们。

PHP is an old programming language.  There are a lot of things that were designed into the language in the 1990's.  That was before hacking, spam, viruses, and other security problems were even beginning to be understood.  As a result, many of the code smells relate to things that seemed convenient at the time, but turned out to be dangerous or wasteful in retrospect.  Unfortunately, bad code examples do not come with expiration dates, and some of them (well, millions of them) are still published on the internet.  They are easy to find and they get copied over and over by novice programmers, perpetuating the bad practices.  If you find a code sample on the internet ask yourself, "When was this written?"  Also, ask yourself, "Do I completely understand what the author as thinking and how it relates to my problem?"  If you're not 100% sure about both of those answers, skip over the example and go look for one that makes more sense to you!  

PHP是一种古老的编程语言。 在1990年代,语言中已经设计了很多东西。 在此之前,黑客,垃圾邮件,病毒和其他安全问题甚至还没有开始被理解。 结果,许多代码的气味与当时看来很方便的事物有关,但事后回想起来却是危险或浪费的。 不幸的是,错误的代码示例没有附带到期日期,并且其中一些(甚至有数百万个)仍在互联网上发布。 它们很容易找到,并且会被新手程序员一遍又一遍地复制,从而使不良做法永久存在。 如果您在互联网上找到代码示例,请问自己:“这是什么时候写的?” 另外,问自己:“我是否完全了解作者的想法以及它与我的问题的关系?” 如果您不确定这两个答案的百分百,请跳过该示例,然后寻找对您更有意义的示例!

These coding horrors are in no particular order, and they may not always cause scripts to fail, data bases to be destroyed, money to be lost, etc.  But they have that potential.

这些编码恐怖没有特别的顺序,它们可能不会总是导致脚本失败,数据库被破坏,资金损失等。但是它们具有这种潜力。

1. Installing the Code Without Understanding the Code

1.在不了解代码的情况下安装代码

For some reason, people feel that they don't need to learn PHP before they start using it!  Unfortunately, the internet is littered with simply terrible examples of PHP code written long ago by novice programmers who did not understand the principles of computer science or security, and who never took the time to clean up after themselves.  And a particularly frequent offender, DreamWeaver, generates some of the worst PHP code ever written.  Copying code from internet resources or DreamWeaver is a sure way to get yourself in trouble.  So don't do that.  Instead stick to quality learning resources from dependable authors.  Like everything else in life, knowing what you're doing with PHP is really helpful.

出于某种原因,人们认为在开始使用PHP之前不需要学习PHP! 不幸的是,Internet上散布着很糟糕PHP代码示例,这些示例是很早以前由不了解计算机科学或安全性原理并且从未花时间自己清理的新手程序员编写的。 尤其是经常犯规的DreamWeaver会生成一些有史以来最糟糕PHP代码。 从互联网资源或DreamWeaver复制代码是使自己陷入困境的可靠方法。 所以不要那样做。 而是坚持使用来自可靠作者的优质学习资源 。 就像生活中的其他一切一样,了解PHP的使用确实很有帮助。

Want a good test for understanding the code?  Try to say or write a one-sentence explanation for every line of code in your script.  If you can do that, you understand the code.  If you find yourself unsure or at a loss for words, stop what you're doing and look up the functions and classes on php.net.  A moment invested in learning can save you from days of debugging.  Further guidance on this point comes to us from Alexander Pope in his elegant Essay on Criticism.

想要通过测试来理解代码吗? 尝试对脚本中的每一行代码说或写一句话解释。 如果可以做到,则可以理解代码。 如果您不确定或不确定,请停止正在执行的操作,然后在php.net上查找函数和类。 花一点时间在学习上可以节省您数天的调试时间。 关于这一点的进一步指导,是亚历山大·波普Alexander Pope)在其优雅的《批评论文》中给我们的。

2. Not Having a Backup Copy

2.没有备份副本

Really?!  You made a change to a deployed production system?!

真?! 您是否更改了已部署的生产系统?

3. Not Having a Test Data Set

3.没有测试数据集

Really?!  You are about to make a change to a deployed production system?!  You might want to rethink that!

真?! 您将要更改已部署的生产系统吗? 您可能需要重新考虑

4. Programming Without Error_Reporting(E_ALL)

4.不带错误报告的编程(E_ALL)

If you do not tell PHP to show you all the errors, you will miss some of the errors!  PHP will suppress the Notice messages unless you ask PHP to tell you the Notice messages.  Always ask any programming language to tell you all of the errors!

如果您不告诉PHP向您显示所有错误,那么您错过一些错误! 除非您要求PHP告诉您NOTICE消息,否则PHP会禁止显示NOTICE消息。 始终要求任何编程语言告诉您所有错误!

5. Suppressing Messages with @

5.用@禁止显示消息

Whenever there is a reason to suppress a warning message, there is an even greater reason to find out the cause of the message and eliminate it!  If I see the @ prepended to a function call, I expect to see the comments explaining why that is a good practice.  In almost every case it's not a good practice, but was an expedient way for a sloppy programmer to avoid a step in the debugging process.  It's significant to note that if you use @ to suppress messages and a Fatal Error occurs in the function, the script will fail silently.  There will be no message or log, and no indication of where the error occurred.  Imagine trying to debug something like that!

只要有理由禁止发出警告消息,就有更大的理由找出造成该消息的原因并将其消除! 如果我看到@放在函数调用的前面 ,我希望看到注释解释为什么这是一个好习惯。 在几乎每种情况下,这都不是一个好习惯,但是对于草率的程序员而言,这是避免调试过程中采取步骤的一种便捷方式。 值得注意的是,如果使用@禁止显示消息,并且函数中发生致命错误,则脚本将静默失败。 将不会有消息或日志,也不会指出错误发生的位置。 想象一下尝试调试类似的东西!

6. Register Globals

6.注册全球

This takes the danger of Globalmania and sprays it randomly and universally into your script.  Disable Register Globals!  If you're at a current level of PHP, it should be disabled already.  Maybe you want to use phpinfo() to verify this.

这冒了Globalmania的危险并将其随机且普遍地喷洒到您的脚本中。 禁用全球注册! 如果您使用的是当前级别PHP,则应将其禁用。 也许您想使用phpinfo()进行验证。

7. Sloppy Syntax and Formatting

7.草率的语法和格式

This is a programmatic shibboleth that screams, "I don't know what I'm doing!"  PHP allows you to write ugly code, very ugly code, and PHP will still interpret it, and if the code does not fail for a parse error, PHP will try to run it.  This is unfortunate, because it leads novice PHP programmers to think that coding standards do not matter, that they can use silly or meaningless variable names, that alignment and readability of the code isn't important.  Nothing could be further from the truth.  Neatness counts, and the reason for neatness and tidy organization is so that humans can make sense of your script.  Those humans include you, if you revisit the programming after a day or two away from the task.  Adopt a coding standard and adhere to it rigidly.  You probably want to adhere to PSR-1 and PSR-2.  With self-discipline comes self-confidence.

这是一个程序化的shibboleth,尖叫着说:“我不知道我在做什么!” PHP允许您编写丑陋的代码,非常丑陋的代码,PHP仍将对其进行解释,并且如果代码没有因解析错误而失败,PHP将尝试运行它。 这是不幸的,因为它使PHP新手程序员认为编码标准无关紧要,它们可以使用愚蠢的或毫无意义的变量名,代码的对齐方式和可读性并不重要。 没有东西会离事实很远。 整洁很重要,整洁和井井有条的原因是为了让人们可以理解您的脚本。 如果您在离开任务一两天后重新访问编程,那么这些人也将包括您。 采用编码标准并严格遵守。 您可能想要遵守PSR-1PSR-2 。 自律带来自信。

7a. Misusing Quotes and Apostrophes

7a。 误用引号和撇号

Quote marks and apostrophes have special meanings in most programming languages and PHP is no exception, providing the novice with an almost endless number of ways to create parse errors with fiddly punctuation.  What do you need to know, when and how to use or avoid them?  See this article about Quotes in PHP Programing

引号和撇号在大多数编程语言中都有特殊含义,PHP也不例外,它为新手提供了几乎无数种使用标点符号创建解析错误的方法。 您需要了解什么,何时以及如何使用或避免使用它们? 请参阅有关PHP编程中的引号的本文

8. Poorly Chosen Variable Names

8.变量名称选择错误

What is the likely meaning of a variable named $x?  It's hard to guess!  If it's expected to be today's date, why not use $today instead?  And if you're retrieving rows from several different queries, beware of using $row.  It's just too easy to get confused.  Instead, strive for meaningful variable names that clearly identify your thought processes.  And in related matters, choose data base column names that you can readily understand and that do not conflict with SQL functions or reserved words.

名为$ x的变量的可能含义是什么? 很难猜! 如果预计今天是今天,那么为什么不使用$ today呢? 而且,如果要从几个不同的查询中检索行,请注意不要使用$ row 。 容易混淆。 取而代之的是,寻找有意义的变量名,以清楚地标识您的思维过程。 在相关事项中,请选择易于理解且与SQL函数保留字不冲突的数据库列名称。

9. Compound Statements

9.复合陈述

We've all seen them... Someone wants to look smart, so they nest a collection of function calls into a single-line statement.  The problem with doing this is pretty simple.  If you get an unexpected return value, you have to take the code apart to find out what screwed up.  Why not just start with the code on separate lines and save yourself a debugging cycle?  PHP does not run any faster when there are compound statements in the script!  PHP has to compile the script before it can be executed, and the compiled output is exactly the same, whether the statements were written legibly or all jammed up together into an unreadable mess.  PHP does not care, so take the easy approach -- the one humans are most likely to understand.  These two blocks of code do the same work.  The signature of compound statements are adjacent closing parentheses.

我们都已经看到它们了……有人想看起来很聪明,因此他们将一组函数调用嵌套在单行语句中 。 这样做的问题很简单。 如果您获得了意外的返回值,则必须将代码拆开以找出导致错误的原因。 为什么不只从单独的代码开始,以节省调试周期呢? 当脚本中包含复合语句时,PHP的运行速度不会更快! PHP必须先对其进行编译,然后才能执行该脚本,并且无论该语句编写得是否清晰,还是所有语句都杂乱地合并在一起,导致编译后的输出完全相同 。 PHP不在乎,因此请采用简单的方法-人类最有可能理解。 这两个代码块执行相同的工作。 复合语句的签名是相邻的右括号。

// NORMALIZE, CAPITALIZE, ESCAPE THE COLOR
$rgb = $mysqli->real_escape_string(ucfirst(strtolower(trim($color))));

// A CLEANER WAY TO NORMALIZE, CAPITALIZE, ESCAPE THE COLOR
$rgb = trim($color);        // REMOVE WHITESPACE
$rgb = strtolower($rgb);    // MAKE ALL LOWER CASE
$rgb = ucfirst($rgb);       // CAPITALIZE FIRST LETTER
$rgb = $mysqli->real_escape_string($rgb); 

9.a Compound Arguments

9.a复合参数

These are closely related to compound statements, and they create a similar problem, to wit, you cannot readily see what data was passed in the argument string.  Consider this example:

这些与复合语句紧密相关,并且它们会产生类似的问题,也就是说,您无法轻易看到在参数字符串中传递了哪些数据。 考虑以下示例:

$res= $mysqli->query($sql2  . $start . ', ' . $limit);  

What does the query string contain?  Who knows?  You would have to print out three variables to begin to figure it out.  A better ways to write the code would look something like this:

查询字符串包含什么? 谁知道? 您必须打印出三个变量才能开始计算。 编写代码的更好方法如下所示:

$sql = $sql2  . $start . ', ' . $limit;
print_r($sql);
$res = $mysqli->query($sql);  

10. Using REGEX to Do Things That PHP Should Do for You

10.使用REGEX做PHP应该为您做的事情

I came across this statement in a client's code recently:

我最近在客户代码中遇到了以下语句:

$regexp="/^[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\.-][a-z0-9]+)*)+\\.[a-z]{2,}$/i"; 

Maybe that made sense (to validate an email address) many years ago, but we've had PHP filter_var() since PHP 5.2.  Regular expressions are very hard to get right!  And they are even harder to get right if they're strung together in a long, uncommented string.  Experienced programmers have a joke that goes, "I had 99 problems, so I used a Regular Expression.  Now I have 100 problems!"

也许很多年前(验证电子邮件地址)很有意义,但是自PHP 5.2起,我们就有了PHP filter_var() 。 正则表达式很难正确设置! 如果将它们串成一条长而没有注释的字符串,则更难正确。 经验丰富的程序员开玩笑说:“我有99个问题,所以我使用了正则表达式。现在我有100个问题!”

11. Writing Code to Do Things That PHP Should Do for You

11.编写代码来执行PHP应该为您做的事情

You wouldn't believe how many novice programmers do not understand the way date() and strtotime() work together.  Instead of using the built-in functionality, they try to write their own date computation algorithms, and the resulting code is almost always overly complicated and usually wrong in the edge cases, like leap year, daylight savings time, changing time zones, etc.  This is not the only place that PHP built-ins get ignored, but it's fairly common.  For another example, see the list of array functions for a collection of things that novices overlook or misunderstand.

您不会相信有多少新手程序员不了解date()strtotime()一起工作的方式。 他们没有使用内置功能 ,而是尝试编写自己的日期计算算法,结果代码几乎总是过于复杂,在极端情况下通常是错误的,例如day年,夏令时,更改时区等。这不是唯一PHP内置程序被忽略的地方,而是相当普遍的地方。 另一个示例,请参见数组函数列表,以了解新手忽略或误解的一系列事物。

12. Using the Wrong Tools

12.使用错误的工具

"Please bring me a wrench," said the carpenter.  

“请给我一把扳手,”木匠说。

"What kind of wrench" said the apprentice, "Pipe wrench, lock wrench, spanner wrench, monkey wrench, Stillsons wrench...?

学徒说:“什么样的扳手?管扳手,锁紧扳手,扳手,猴子扳手,斯蒂尔森斯扳手...?

"Doesn't matter -- I'm just going to use it to pound nails."

“没关系-我将用它来钉钉子。”

File systems and data bases are different kinds of storage, and understanding the differences is an important part of application development.  Have you ever seen anyone store image files in a data base BLOB?  You won't see them doing it for very long, because as the image collection grows the data base will become slower and slower, impossible to back up, and generally an impediment to application deployment.  If you start down this path, expect to find yourself refactoring (or maybe someone else will be refactoring because you will get fired).  Image files (and by extension, sound or multimedia files) belong in the server file system.  The associated data base information should contain the URL of the image, not the image file.

文件系统和数据库是不同类型的存储,理解差异是应用程序开发的重要部分。 您是否见过有人将图像文件存储在数据库BLOB中? 您不会看到他们这样做太久了,因为随着图像收集的增长,数据库的速度将越来越慢,无法备份,并且通常会阻碍应用程序的部署。 如果您沿着这条路走,请期待自己进行重构(或者其他人可能正在重构,因为您将被解雇)。 图像文件(以及扩展名,声音或多媒体文件)属于服务器文件系统。 关联的数据库信息应包含图像的URL,而不是图像文件。

The flip side of this misstep is seen in applications where some well-intentioned but misinformed designer created a flat text file or an XML document so he could store his files without using a data base.  Usually this happens when the designer is trying to avoid learning what a data base does.  The problem with this approach is not performance, but functionality.  XML is by its nature hierarchical.  A data base is relational.  The first time you have to find the relationships in an XML document, you will wish you had learned about data bases instead!

在应用程序中可以看到这种错误步骤的另一面,其中一些善意却误导了信息的设计师创建了纯文本文件或XML文档,因此他可以在不使用数据库的情况下存储文件。 通常,这发生在设计人员试图避免了解数据库功能的情况下。 这种方法的问题不是性能,而是功能。 XML本质上是分层的 。 数据库是关系数据库 。 第一次必须在XML文档中查找关系时,您希望自己已学习数据库!

13. Failure to Put Comments Into the Code

13.无法在代码中添加注释

It doesn't always have to be a doc-block, but there should be something to tell people what you're thinking and what you're trying to do!  And a doc-block never hurts.  It can provide tips and code hinting in some IDEs.

它不一定总是必须是文档块 ,但应该有一些内容可以告诉人们您在想什么和您想做什么! 而且,文档阻止永远不会伤害您。 它可以在某些IDE中提供提示和代码提示。

14. Using the ?> Close-PHP Tag

14.使用?> Close-PHP标记

This tag is almost invariably followed by an invisible whitespace end-of-line character, which is browser output.  It can and will cause more trouble than it's worth.  Especially because it is invisible!  Unless you absolutely require the close PHP tag, omit it.  Really, PHP knows when it's finished!  Even if DreamWeaver doesn't!

这个标签几乎总是跟在不可见的空白行尾字符,这是浏览器输出。 它会并且将会造成比其价值更大的麻烦。 特别是因为它是隐形的! 除非您绝对需要关闭PHP标记,否则请忽略它。 确实,PHP知道何时完成! 即使DreamWeaver不这样做!

15. Using the Global Keyword

15.使用全局关键字

This is really only needed when the application designer hasn't given enough thought to the organization of the data and classes.  It's a signature of disorganized thinking.  Avoid global variables.  Pass parameters and return values instead.

仅当应用程序设计人员对数据和类的组织没有足够的考虑时,才真正需要这样做。 这是思维混乱的标志。 避免使用全局变量。 传递参数并返回值

16.$_REQUEST

16. $ _REQUEST

Avoid using the $_REQUEST variable.  The reason for this is simple: you do not know where the request data came from!  Was it from your HTML form?  Or did a malicious person simply type the request variables into the URL?  If you choose $_POST and $_GET you at least know the request method.  It does not protect you from hack attacks, but it makes them a little harder to perpetrate.

避免使用$ _REQUEST变量。 原因很简单:您不知道请求数据来自何处! 是来自您HTML表单吗? 还是恶意者只是将请求变量键入URL? 如果选择$ _POST和$ _GET,则至少知道请求方法。 它不能保护您免受黑客攻击,但会使攻击更难进行。

Another reason to avoid $_REQUEST is because of the request_order directive.  This (positively stupid) configuration variable can cause the same script to produce different outputs if the directive is changed.  Why did PHP introduce this stumbling block at 5.3?  Your guess is as good as mine!

避免$ _REQUEST的另一个原因是因为request_order指令。 如果更改指令,则此(肯定是愚蠢的)配置变量可能导致同一脚本产生不同的输出。 为什么PHP在5.3引入了这个绊脚石? 你的猜测和我的一样好!

17.Extract()

17. Extract()

Like the use of register_globals, any programming that injects unnecessary variables into the symbol table has a bad code smell.  The wise programmer avoids variable proliferation.

像使用register_globals一样 ,任何将不必要的变量注入到符号表中的程序都具有不良的代码味道。 明智的程序员应避免变量扩散。

18. Writing Your Own Version of Extract()

18.编写您自己的Extract()版本

You may have seen something like this:

您可能已经看到以下内容:

$u = $_POST["username"];
$p = $_POST["password"]; 

This accomplishes nothing.  It just copies one variable to another, creating two versions of the same data.  Perhaps the programmer forgot about filter_var()?  It also introduces a subtle psychological element of trust that is completely misplaced.

这什么也做不了。 它只是将一个变量复制到另一个变量,从而创建相同数据的两个版本。 也许程序员忘记了filter_var() ? 它还引入了一种微妙的信任心理要素,这种要素被完全放错了位置。

$u = $_POST['username'] only copies the contents of $_POST['username'] into the variable named $u.  Whatever was present, good or bad, in the original POST request variable is now "conveniently" addressable inside the shorthand $u.  The act of including the unfiltered attack vector in a more convenient variable name is one big part of this anti-practice, because it seems to encourage the use of shorthand $u instead of the longhand and more explicit $_POST['username'].  It seems to me that $_POST is a highly recognizable external variable, and therefore readily identified as a tainted data source.  Not so, for $u, and it requires us to read the code and follow $u back to its origin before we can know whether to trust $u.  So if you're going to create a shorthand notation, filter and sanitize the data before assigning it to the shorthand variable. 

$ U = $ _ POST [“用户名”]只复制$ _ POST [“用户名”]的内容到名为$ U中的变量。 现在,无论在原始POST请求变量中是好是坏,无论是好是坏,都可以在速记$ u内部方便地进行寻址。 在更方便的变量名中包含未过滤的攻击向量的行为是此反实践的重要组成部分,因为它似乎鼓励使用速记$ u代替速记$ uPOST和更明确的$ _POST ['username']。 在我看来, $ _POST是一个高度可识别的外部变量,因此很容易被识别为受污染的数据源。 并非如此,对于$ u ,它要求我们阅读代码并跟随$ u回到其起源,然后才能知道是否信任$ u 。 因此,如果要创建速记符号,请将数据分配给速记变量之前对其进行过滤和清理。

This anti-practice is an example of failure to sanitize external data, as shown below.

如下所示,此反实践是无法清除外部数据的一个示例。

19. Failure to Filter/Sanitize External Data

19.无法过滤/清理外部数据

Here is the classic screwup:

这是经典的组装:

$sql = 'DELETE FROM myTable WHERE id = ' . $_GET['id']; 

Do you have any idea how many rows will be deleted?  No, you do not.  Maybe you think it is only one row?  But there is no LIMIT clause.  Want to know how common this blunder is?  In November, 2013, Michelangelo Van Dam gave a presentation to the Washington DC PHP Users Group in which he searched GitHub for the intersection of mysql_query() and $_GET.  This is what we saw.

GitHub Search
What if $_GET['id'] came from a URL that said: url.php?id=0+OR+1+=+1

您知道要删除多少行吗? 你不可以。 也许您认为只有一排? 但是没有LIMIT子句。 想知道这种错误有多普遍吗? 2013年11月, 米开朗基罗·范丹Michelangelo Van Dam )向华盛顿特区PHP用户组作了介绍,他在GitHub上搜索了mysql_query()$ _GET的交集。 这就是我们所看到的。 如果$ _GET ['id']来自URL: url.php?id = 0 + OR + 1 + = + 1怎么办?

The resulting query would say DELETE FROM myTable WHERE id = 0 OR 1 = 1 and the OR condition would apply to every row of myTable. Bang! You're Fired!  This anti-practice has been an object of ridicule for years.  It's as dangerous as driving on the wrong side of the road.  Yet for some odd reason, there are still programmers who have not heard of the issue.  See http://xkcd.com/327/

结果查询将说, 从myTable中删除ID为0或1 = 1的myTable,并且OR条件将应用于myTable的每一行。 砰! 你被开除了! 多年来,这种反实践一直是人们嘲笑的对象。 这就像在错误的道路上行驶一样危险。 但是由于某些奇怪的原因,仍然有一些程序员没有听说过该问题。 参见http://xkcd.com/327/

19.a Relying on JavaScript to Filter/Sanitize External Data

19.a依靠JavaScript过滤/清理外部数据

A variant on failing to filter external data is relying on client-side technologies to do the work that must be done on the server-side (see the relationship here).  JavaScript and jQuery are used to make a nice experience for your human client, but they provide no protection at all against an attack because the attackers will simply bypass the client-side niceties and will post toxic data directly into your application.  This is easily accomplished with cURL or fsockopen() and the attack can even be tailored to look like it's coming from a browser that was referred by the HTML form on your web site.  All external data is, by definition, tainted, full stop.  You must filter it with server-side tools, after it has been received on the server.

无法过滤外部数据的一种变体是依靠客户端技术来完成必须在服务器端完成的工作( 请参阅此处的关系 )。 JavaScript和jQuery用于为人类客户带来良好的体验,但是它们根本无法提供针对攻击的保护,因为攻击者只会绕过客户端的细节,并将有毒数据直接发布到您的应用程序中。 这可以通过cURLfsockopen()轻松完成,甚至可以对攻击进行定制,使其看起来像是来自网站上HTML表单所引用的浏览器。 所有的外部数据,顾名思义, 污点 ,句号。 在服务器上收到它之后 ,必须使用服务器端工具对其进行过滤。

20. Failure to Escape External Data

20.无法转义外部数据

The query says, "INSERT INTO myTable (name) VALUES ({$_POST['name']}" and that should work, right?  Sure, until you find someone named O'Reilly.  Then you have a stray apostrophe in your query string, and that's a recipe for failure.  Apostrophes have a special meaning in query strings, unless you escape them.

该查询显示“ INSERT INTO myTable(name)VALUES({$ _POST ['name']}}”,对吗,对吗?确定,直到找到一个名为O'Reilly的人为止。然后在查询中有一个撇号字符串,这是失败的秘诀。撇号在查询字符串中具有特殊含义 ,除非您将其转义

21. Double Escape of External Data

21.外部数据的双重转义

Consider the PHP environment is set up with Magic Quotes, and the programmer, not sure about this, uses addslashes() or similar functions to escape the data.  As a result the data base is cluttered with double backslashes.  A common symptom of this misstep is code that uses stripslashes() on the fields that are drawn from the data base.

考虑到PHP环境是使用Magic Quotes设置的,并且程序员对此不确定,因此使用addlashes()或类似函数来转义数据。 结果,数据库中充斥着两个反斜杠。 这种错误的常见症状是在从数据库中提取的字段上使用stripslashes()的代码。

22. Failure to Escape Client Output

22.无法转义客户端输出

Envision a script reads an input field and stores it in the data base, then later it echoes the data out to a client browser.  What could possibly go wrong?  Well, the input field could have been poisoned with toxic JavaScript that will cause the client browser to begin an action that is harmful to the client computer and eventually to the client human.  When you see echo statements without htmlspecialchars(), you have to wonder...

设想脚本读取输入字段并将其存储在数据库中,然后稍后将数据回显到客户端浏览器。 可能出什么问题了? 好吧,输入字段可能已经被有毒JavaScript毒害了,这将导致客户端浏览器开始执行对客户端计算机乃至客户端人类有害的操作。 当您看到没有htmlspecialchars()的 echo语句时,您不得不怀疑...

23. Uninitialized Variables

23.未初始化的变量

http://xkcd.com/1193/ shows what can go wrong if you don't know what a variable contains.  Unfortunately PHP suppresses Notice level messages by default.  So novice programmers think it is OK to use uninitialized variables to mean FALSE or zero or an empty string, because that level of offense only rises to the level of a PHP Notice.  You can get away with this right up until the time that your manager wants to make a small change to your script and she chooses the variable name you were assuming would be empty or set with a value you expected.  If you raise the error_reporting() level to show the Notice messages, PHP will tell you about this pitfall.

http://xkcd.com/1193/会显示如果您不知道变量包含的内容可能会出错。 不幸的是,默认情况下,PHP禁止显示通知级别的消息。 因此,新手程序员认为使用未初始化的变量表示FALSE或零或空字符串是可以的,因为该错误级别只会上升到PHP Notice的级别。 直到经理想要对脚本进行小的更改并且她选择假定的变量名称为空或使用您期望的值进行设置之前,您都可以避免使用它。 如果您提高error_reporting()级别以显示Notice消息,PHP会告诉您有关此陷阱的信息。

24. Failure to Test the Return Values from PHP Functions

24.无法测试PHP函数的返回值

You wouldn't believe how many times the same programming error occurs, over and over, because something like this gets copied and perpetrated again and again.

您不会相信相同的编程错误会一遍又一遍地发生,因为类似的事情会一次又一次地被复制和执行。

$res = mysql_query($sql);
while ($row = mysql_fetch_assoc($res)) { ... 

What's wrong here is the assumption that the return value in $res is a query result resource.  It might not be!  It might be FALSE.  If the program does not test for this condition, the script will eventually fail silently or with data damage.  MySQL is not a black box.  It can and will fail for reasons that are outside of the PHP programmers' control.  If your script cannot control something, it must test for the uncontrollable condition (in this case, query failure) and handle the conditions as they arise.

这里的错误是假设$ res中的返回值是查询结果资源 。 可能不是! 可能是FALSE。 如果程序没有对此条件进行测试,则脚本最终将无提示地失败或导致数据损坏。 MySQL不是黑匣子。 由于PHP程序员无法控制的原因,它可能并且将失败。 如果脚本无法控制某些内容,则它必须测试无法控制的条件(在这种情况下为查询失败),并在条件出现时进行处理。

25. Wasting Time Not Knowing What Happened

25.浪费时间不知道发生了什么

Script failed, no output, what's wrong?  Well, the first thing to do is start creating output!  Use var_dump() to print out the inputs your script is receiving.  And to print out the intermediate variables.  And to visualize the data before the output phase.

脚本失败,无输出,怎么了? 好吧,第一件事就是开始创建输出! 使用var_dump()打印出脚本正在接收的输入。 并打印出中间变量。 并在输出阶段之前可视化数据。

25.a Wasting Other People's Time Not Knowing What Happened

25.a浪费别人的时间不知道发生了什么

It's amazing how many questions are posted here at EE with a code example and the question, "what's wrong?"  The code is useless; we already know it doesn't work.  What we really need to see instead is the data.  If your data takes the form of a return object (for example, from an API) and you post the output of print_r() or var_dump() we can read it, but it's unwieldy when we want to write some code that works with the data.  PHP has a perfect tool for solving this problem.  It's a built-in function, var_export().  Look it up, learn it now, test it out, and please use it when you want to show a colleague your test data.  And since PHP is still a "living language" with some things that are only half-baked, you may also want to read this note.  Var_export() may need help to work with StdClass.

令人惊讶的是,在EE上用代码示例发布了多少个问题以及“什么地方错了?”这个问题。 该代码是无用的。 我们已经知道它不起作用。 相反,我们真正需要查看的是数据 。 如果您的数据采用返回对象的形式(例如,来自API),并且您发布了print_r()var_dump()的输出,我们可以读取它,但是当我们想编写一些与数据。 PHP具有解决此问题的完美工具。 这是一个内置函数var_export() 。 查找它, 现在学习它,进行测试,如果要向同事显示您的测试数据,请使用它。 而且由于PHP仍然是“活的语言”,有些东西还只是半生半熟,因此您可能还需要阅读本说明。 Var_export()可能需要帮助才能与StdClass一起使用

http://www.php.net/manual/en/reserved.classes.php#113971

http://www.php.net/manual/zh/reserved.classes.php#113971

26. Wasting Time on Meaningless Optimization

26.浪费时间进行无意义的优化

Not limited to PHP by any means, but PHP programmers seem particularly interested in minutiae like whether it is faster to iterate over an array or an object.  The answer is, "it doesn't matter."  These kinds of pursuits are like milking a mouse.  No matter how much effort you put into the process, you will not get much.

无论如何,不​​限于PHP,PHP程序员似乎对细节有特别的兴趣,例如迭代数组或对象的速度是否更快。 答案是“没关系”。 这些追求就像在给老鼠挤奶。 无论您在该过程中付出了多少努力,您都不会得到太多。

http://xkcd.com/1205/

http://xkcd.com/1205/

27. Overlooking Meaningful Optimization

27.忽略有意义的优化

Data transfers via disk I/O operations are several orders of magnitude slower than in-memory data transfers, and when there is a performance problem in a web application it is usually found in the data base.*  You need to know how your database works and how to optimize the data base and script file structure.  Here are some topical questions to ask yourself.

通过磁盘I / O操作进行的数据传输比内存中的数据传输要慢几个数量级,并且当Web应用程序出现性能问题时,通常会在数据库中找到它。*您需要知道数据库的工作方式以及如何优化数据库和脚本文件结构。 以下是一些要问自己的话题。

Are your scripts using something like MySQL_Fetch_Array()?  Perhaps you copied that from one of the many bad PHP examples that litter the internet?  Change that function to a variant of Fetch_Assoc() or better yet, Fetch_Object().  The Fetch_Array() variant retrieves twice as much data as is needed, making it the least efficient way to retrieve your data.

您的脚本是否使用类似MySQL_Fetch_Array()的东西? 也许您是从众多在互联网上乱糟糟PHP示例之一复制了这一点? 该功能更改为的变体FETCH_ASSOC()或更好,但Fetch_Object() 。 Fetch_Array()变量检索的数据量是所需数据的两倍,这使其成为检索数据效率最低的方法。

Do you have a SELECT * query?  If so, eliminate the * and put in the names of the columns you want to retrieve.  SELECT * retrieves all of the columns, even the ones you do not need, making it the least efficient way to retrieve data.

您是否有SELECT *查询? 如果是这样,请消除*并输入要检索的列的名称。 SELECT *检索所有列,甚至不需要的列,这使其成为检索数据效率最低的方法。

Do you have a SELECT query that is expected to retrieve one row (such as a user-id lookup or a single inventory item)?  If so, be sure you have LIMIT 1 in the query.  Failure to LIMIT the query will result in a table scan, making it the least efficient way to find the information.

您是否有预期检索一行 (如用户ID查找或单个存货项目)SELECT查询? 如果是这样,请确保查询中有LIMIT 1。 未能限制LIMIT的查询将导致表扫描,这使其成为查找信息效率最低的方法。

Does your code loop around to add values as it retrieves the results set from the MySQL server? Maybe you should be using server side aggregations with a GROUP BY clause.

在从MySQL服务器检索结果集时,您的代码是否会四处循环以添加值? 也许您应该使用带有GROUP BY子句的服务器端聚合。

Are your data base tables appropriately indexed?  You may want to have an index on every column used in WHERE, ORDER, GROUP, JOIN and HAVING clauses.

您的数据库表是否已正确索引? 您可能希望在WHERE,ORDER,GROUP,JOIN和HAVING子句中使用的每个列上都有一个索引。

Are your queries sargable?

您的查询是否可靠

Have you used EXPLAIN SELECT to optimize queries that touch more than one table?

您是否使用EXPLAIN SELECT来优化涉及多个表的查询?

If you recognize some of these issues in your queries, or more importantly, don't understand some of them, you might want to read this excellent article by our EE colleague, gr8gonzo.  Entire books are devoted to MySQL and optimization, especially at large scale, is a highly technical and detailed endeavor.  But every programmer should have an understanding of the basics.

如果您在查询中发现了其中一些问题,或者更重要的是,您不理解其中的一些问题,那么您可能想阅读我们的EE同事gr8gonzo撰写的 精彩文章 。 整本书都致力于MySQL和优化,尤其是大规模的优化,这是一项技术性很强的详细工作。 但是每个程序员都应该对基础有所了解。

* Or sometimes in the API calls to other applications with slow data base queries!

*或有时在API调用中以缓慢的数据库查询来访问其他应用程序!

28. Skipping Best Practices

28.跳过最佳做法

You really want to just get it done fast, right?  See http://xkcd.com/292/  The cartoon is a joke, but the best practices are not.  They are the way experienced programmers have learned to get the best and fastest results.

您真的想快速完成它 ,对吧? 请参阅http://xkcd.com/292/卡通是个玩笑,但最佳实践却不是。 它们是经验丰富的程序员学会获得最佳和最快结果的方式

29. Manipulative Programming

29.操纵编程

(Added in 2016) Undoubtedly you've been in a conversation with a technical manager who has no sense of marketing, and something like this has come up: "How can we force the users to ___ (fill in the blank)?"  The answer is not found in technical details; it's found in human nature and common sense.  If your clients feel like they are being coerced, they will go away, and that is that.  One obvious manifestation of this anti-practice is demanding that clients fill out a registration form before they can see free information, or refusing to accept forms until they are complete, or making a web site that fails if it cannot set HTTP cookies.  Don't do things that drive customers away!  Instead, be as open and informative and inviting as you can be.  You can bet your competitors are trying to be nice to your clients.  Don't lose your customers over a design flaw.

(在2016年添加)毫无疑问,您正在与没有市场营销意识的技术经理进行对话,并且出现了类似的情况:“我们如何迫使用户___ (填空) ?” 在技​​术细节中找不到答案。 它是在人的天性和常识中发现的。 如果您的客户觉得自己受到胁迫,他们就会走开,就是这样。 这种反实践的明显体现是要求客户在看到免费信息之前先填写注册表,或者要求客户在完成之前拒绝接受表单,或者要求网站设置无法设置HTTP Cookie的网站而失败。 不要做会把顾客赶走的事情! 取而代之的是,尽可能地保持开放,信息丰富和诱人。 您可以打赌您的竞争对手正在努力对您的客户好。 不要因设计缺陷而失去客户。

Summary

摘要

Knowing what to do is important, and so is knowing what not to do.  Do you have some examples of wrongheaded designs and practices?  Please share them in the article comments below.  If we're smart about things, we can learn to avoid the AntiPHPractices, choosing best practices instead.

知道做什么是重要的,所以知道什么是不该做的。 您是否有一些错误的设计和实践示例? 请在下面的文章评论中分享它们。 如果我们对事物很聪明,我们可以学习避免使用AntiPHPractices,而选择最佳实践。

Please give us your feedback!

请给我们您的反馈意见!

If you found this article helpful, please click the "thumb's up" button below. Doing so lets the E-E community know what is valuable for E-E members and helps provide direction for future articles.  If you have questions or comments, please add them.  Thanks!

如果您发现本文有帮助,请单击下面的“竖起大拇指”按钮。 这样做可以使EE社区了解对EE成员有价值的内容,并为将来的文章提供指导。 如果您有任何问题或意见,请添加。 谢谢!

翻译自: https://www.experts-exchange.com/articles/12293/AntiPHPatterns-and-AntiPHPractices.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值