《PHP设计模式介绍》第一章 编程惯用法 学习一门新的语言意味着要采用新的惯用法。这章将介绍或者可能重新强调一些惯用法。你会发现这些惯用法在你要在代码中实现设计模式时候是非常有用的。
测试你的代码
可能没有什么代码惯用法比测试代码更加重要了。好的测试可以提高开发速度。
可能一开始,这句格言会和你的直觉相矛盾。你可能会断言,测试是自由的障碍物。事实上恰恰相反,如果你十分完整的运行那些测试来检查你的软件的公共接口,你就可能在不改变(或者更加糟糕,破坏)原来的应用软件的前提下改变自己系统内在的执行。测试并检验你的公共接口的精确性和正确性,并且让自己随意改变一些代码的内在工作来确保你的软件是正确而且没有bug(错误)。
考虑下面的代码
<?php // PHP4 // the subject code define(‘TAX_RATE', 0.07); function calculate_sales_tax($amount) { round($amount * TAX_RATE,2); } // include test library require_once ‘simpletest/unit_tester.php'; require_once ‘simpletest/reporter.php'; // the test class TestingTestCase extends UnitTestCase { function TestingTestCase($name='') { $this->UnitTestCase($name); } function TestSalesTax() { $this->assertEqual(7, calculate_sales_tax(100)); } } // run the test $test = new TestingTestCase(‘Testing Unit Test'); $test->run(new HtmlReporter());
上面的代码首先定义了一个常量——TAX_RATE,和一个计算销售税的函数。接着,代码包含了使用SimpleTest框架的必备组件:单体测试本身和一个用来显示测试结果的“reporter”模块。
类TestingTestCase继承于SimpleTest框架的UnitTestCase类。通过扩展UnitTestCase,类TestingTestCase里面所有使用Test开头的方法都将被认为是测试实例——创造条件来调试你的代码并断言结果。
TestingTestCase定义了一个测试,TestSalesTax(),它包含了一个断言函数AssertEqual()。如果它的前两个输入参数是相等的,它将返回true,否则返回false。(如果你想显示assertEqual()失败的信息,你可以传入三个参数就像这样$this->assertEqual(7,calculate_sales_tax(100), “The sales tax calculation failed”))。
代码的最后两行创建了这个测试实例的实体并且使用一个HtmlReporter运行了它。你可以访问这个web页面来运行这个简单的测试。
运行这个测试将显示测试名称,失败断言的详细情况和一个总结条。(绿色的意味着成功(所有的断言都通过了),而红色的暗示着失败(至少有一个断言没有通过))
(assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。一般来说,assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能,在软件发布后,assertion检查通常是关闭的。)
注:(assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。一般来说,assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能,在软件发布后,assertion检查通常是关闭的。)
上面的代码有一个(有意的)错误,所以运行是不能通过了,显示结果如下:
Calculate_sales_tax()这么一个简单的才一行的函数哪里出错了呢?你可能已经注意到这个函数没有返回结果。下面是正确的函数:
function calculate_sales_tax($amount) { return round($amount * TAX_RATE,2); }
修改后运行,测试通过。
但是一个简单的测试并不能保证代码是稳定的。比如,你把calculate_sales_tax()改成 function calculate_sales_tax($amount) { return 7; },代码也会通过测试,但只有当1美元等价于100的时候才是正确的。你可以自己增加一些额外的测试方法来测试其他的静态值。
function TestSomeMoreSalesTax() { $this->assertEqual(3.5, calculate_sales_tax(50)); }
或者改变函数TestSalesTax()来验证第二个(和第三个,等等)值,如下所示
function TestSalesTax() { $this->assertEqual(7, calculate_sales_tax(100)); $this->assertEqual(3.5, calculate_sales_tax(50)); }
到目前为止还有一种更好的方法,就是新增加一个测试:选择随即值来测试你的代码。具体如下:
function TestRandomValuesSalesTax() { $amount = rand(500,1000); $this->assertTrue(defined(‘TAX_RATE')); $tax = round($amount*TAX_RATE*100)/100; $this->assertEqual($tax, calculate_sales_tax($amount)); }
TestRandomValuesSalesTax()引入了方法assertTrue(),如果传入的第一个变量等于于布尔真则assertTrue()通过。(和方法assertEqual()一样,方法assertTrue()在接受一个可选择性的、额外的后将返回一个失败的信息)。所以TestRandomValuesSalesTax()首先认为常量TAX_RATE已经定义了,然后使用这个常量来计算随机选择的的数量的税收。
但是TestRandomValuesSalesTax()也存在一个问题:它很大程度的依赖于方法calculate_sales_tax()。测试是应该和特殊的实现细节无关的。一个更好的测试应该只建立一个合理的分界线。接下来的这个测试假定销售税永远不会超过20%。
function TestRandomValuesSalesTax() { $amount = rand(500,1000); $this->assertTrue(calculate_sales_tax($amount)<$amount*0.20); }
确保你的代码正常工作是测试的首要的目的,但是在测试你的代码时候,你应该认识到除此之外还有一些额外的,相对次要的目的:
测试让你书写容易测试的代码。这使得代码松散耦合,复杂设计,而且具有很好的模块性。
测试能让你清晰的了解运行代码的期望结果,让你从一开始就注重于模块的设计和分析。通过测试,也会让你考虑所有可能的输入和相应的输出结果。
测试能很快速的了解编码的目的。换句话说,测试事例扮演着“实例”和“文档”的功能,准确的展示着如何构建一个类,方法等。在这本书中,我有时候通过一个测试事例来演示代码的期望功能。通过读取一个测试方法的声明,你可以清楚的了解代码是如何运行的。一个测试实例定义在代码在明确惯用法下的运行情况。
最后,如果你的测试集——测试实例的集合——是非常彻底的,而且当所有的测试都通过的时候,你可以说你的代码是完备的。有趣的是,这个观点也恰好是Test Driven Development(测试驱动开发)的特征之一。
Test Driven Development(TDD)也被认为是Test First Coding(编码前测试)。Test First Coding是一种把测试更提前一步的方法:在你写任何代码之前先写好测试。你可以从http://www.php.cn/下载到一份很好的,简洁的关于TDD的摘要文章,同时下载到一本很好的关于策略的入门书——Kent Beck著作的《Test Driven Development:By Example》(这本书的例子都是用JAVA开发的,但其中代码的可读性是很好的,而且对主题的介绍和说明都做的很好的)。
注:敏捷开发(Agile Development)
最近,单体测试——特别是测绘驱动开发——已经和敏捷开发方法学紧密的联系起来了,比如说极限编程(XP)。极限编程的焦点关注于快速的反复的发步功能性的代码给客户,并把变化的客户需求做为开发过程中的必备部分。下面是一些关于学习敏捷编程的在线资源:
函数性测试
这本书里面的大部分测试例子都是用来测试面对对象的代码,但是所有形式的编程都可以从中得到收获的。单体测试框架,比如说PHPUnits和SimpleTest,也都能很容易的用来测试功能函数的。例如上面的SimpleTest例子,它就是用来测试calculate_sales_tax()函数的。世界各地的程序员们:把单体测试用例放到你的函数库里面吧!
其他实践
下面还有集中其他的实践习惯值得提及到的,也值得加入到你自己的编程习惯里面的。
UML
统一建模语言(UML)是一种与具体编程语言无关的用来描述面对对象编程观念的方法。关于UML的相关信息资料你可以从http://www.php.cn/上找到。
UML涉及到很多方面,但对PHP程序员来说,其中最相关的两方面是类图和序列图。
类图描述了一个或者更多的类以及他们在你的程序之间的相互关系。(译者注:最好能够参考相关的UML教材,将有助于你的理解。)每个类都用一个盒子标识,每个盒子都分成三部分:第一部分是类名,第二步分列举了类的属性(变量),最后一部分列举了类的方法。属性和方法的可见度被设计为:+代表public(公开),—代表private(私有),#代表protected(受保护的)。
序列图描述了为一个特定的任务或者事件,你对代码中的对象之间的典型的交互活动。一个序列图主要传达这样的信息:谁,以什么样的顺序,在什么时候,调用不同的方法(由名字也可以看出:“序列图”)。序列图是对象集和开发人员之间交互沟通的非常有用工具。
在我自己的工程里,我使用这两种典型的类图来勾画我们的设计,但是很少能将他们格式化到项目文档里面。对象之间的关系经常随着你对系统理解的深化和用户需求的变化而改变,因此这些图表很快就会过时。这也就是说“一张图足足值一千个文字”。这些图表对新开发人员理解系统是非常由帮助的,也能做为使用你软件的开发人员的手册。
资源控制
“及时的、经常性的保存”是开发人员另外一个有用的格言。即使你是这个项目的唯一的开发人员,你也应该维持所有的资源处于控制下。
网上可以获取到很多关于资源控制的解决方法,其中两个出色:CVS(http://www.php.cn/)和Subversion(http://www.php.cn/)。CVS是一个非常流行的用于解决PHP和Apache项目的工具。同时,Subversion也正在迅速的成为流行的二选一工具之一,因为它克服了CVS的一些不足之处(特别是在原语命令和删除/重命名文件夹或文件方面)。然而很少有项目安装Subversion服务器。
在工作的时候,我采用CVS,但这本书的代码都是使用Subversion来维护的。
资源代码文档
如果你浏览完了这本书的所有页面,你可以会注意到一些明显的格式化的注释块类似于:
/** * funny multi-line comments * @something what is this? */
它们被称为“docblocks”(译者注:文档块),是由程序,比如说phpDocumentor(http://www.php.cn/),为你的PHP项目自动生成的应用程序接口(API)文档。
Docblocks(文档块)是特定格式的多行注释,以/**标识开始,接下来的每行都以*为第一个字符,并以*/标识注释终止。在每行的前缀前面允许有空格。
@something 代表一个“标签”(tag),当文档需要转化为解析格式时,标签用来阐明一些必要的信息。比如说标签@private,使用在php4中,常用来标识类的这个方法或者属性时私有的,因为在php4中时没有提供这种天然的能力的(译者注:在php4中时无法说明一个变量或者方法是否私有的)。
资源代码文档比如说docblocks即是一个有用的参考资料,也是开源项目的一个好广告。其中一个例子(我帮忙维护的)就是SimpleTestAPI文档(http://www.php.cn/)。

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

在php中,可以使用substr()函数来读取字符串后几个字符,只需要将该函数的第二个参数设置为负值,第三个参数省略即可;语法为“substr(字符串,-n)”,表示读取从字符串结尾处向前数第n个字符开始,直到字符串结尾的全部字符。

方法:1、用“str_replace(" ","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\ \;||\xc2\xa0)/","其他字符",$str)”语句。

php判断有没有小数点的方法:1、使用“strpos(数字字符串,'.')”语法,如果返回小数点在字符串中第一次出现的位置,则有小数点;2、使用“strrpos(数字字符串,'.')”语句,如果返回小数点在字符串中最后一次出现的位置,则有。


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

WebStorm Mac version
Useful JavaScript development tools

DVWA
Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver Mac version
Visual web development tools

Notepad++7.3.1
Easy-to-use and free code editor
