【IT168 PHP开发】如果你来这里是想学习基本的PHP4或者PHP5知识,那这就是为你准备的,开始享受吧!
基本知识
如果你一直吸取常规剂量的PHP知识,那么你现在就应该知道足够的PHP知识来编写你自己的简单程序。然而,这些程序将会是“程序化”的或者直线型的(程序中的语句将会按照顺序一条接一条的来执行),这只不过是因为它是我目前为止所使用的唯一的编程风格而已。
正如你知道,他们所说的关于一些知识的事情是比较危险的, 因为你的PHP脚本变得越来越复杂,你将会因为程序方法的局限性而感到头痛,然后开始寻找更加有效的组织PHP程序的方法,而这只是时间问题。
那就是本章所涉及到的内容。在此章中,我将会为你介绍一种新的编程方法,该方法中的代码并不是按照直线方式运行的,而是在脚本中跳跃交织着运行。这种实现方法的大部分是由一种称为“函数”的编程结构来实现的,并且该教程将教你如何构建函数(只需一次)、使用函数(可多次)、向函数传递参数,以及让函数返回值,以及通常情况下使你的脚本更加紧凑,有效和可维护。
简单说明
让一个技术人员来定义术语“函数“,他可能喃喃而语将“函数”定义为“可分组在一起称为一个可命名实体的语句块”。因为这是关于PHP的教程,而不是关于希腊语的介绍性课程,我将为你们把上述定义翻译如下:函数简单来讲就是执行一个特定任务的一组程序语句,它可以在你的程序的任何一个地方被“调用”或者执行。
每种编程语言都有其自身内建的函数,而且通常情况下,也允许开发者定义其自己的函数。举例而言,如果在我的桌子上有一份年利润报告书,而且我想给其中的每个数字都增加35%,那么我可以给我附近的会计公司打电话让他们为我做这件事情,或者我可以写一个称为cheatTheShareholders()的简单的PHP函数,让它为我做这件工作(它更快,而且PHP不按小时收费)。
有三个重要的原因可以解释为什么说函数是个好东西。首先,用户定义的函数允许你将代码分解成容易识别的代码段(它更容易理解和调试)。其次,函数使你的程序模块化,允许你写一段代码且接着在同一个程序中多次重用该代码。最后,函数简化了代码更新或者变化,因为这种变化只需要在一个地方(函数定义的地方)实现即可。因而函数节省了时间、资金,等等。
“周一早上忧虑症候群”
为了弄明白函数是如何工作的,请看下面的例子:
<?php // define a function function myStandardResponse() { echo "Get lost, jerk!<br /><br />"; } // on the bus echo "Hey lady, can you spare a dime? <br />"; myStandardResponse(); // at the office echo "Can you handle Joe's workload,
in addition to your own,
while he's in Tahiti for a month?
You'll probably need to come in early and work till midnight,
but we are confident you can handle it.
Oh, and we can't pay you extra because of budgetary constraints...<br />"; myStandardResponse(); // at the party echo "Hi, haven't I seen you somewhere before?<br />"; myStandardResponse(); ?>
输出结果如同下面所示:
Hey lady, can you spare a dime?
Get lost, jerk!
Can you handle Joe's workload, in addition to your own, while he's in Tahiti for a month?
You'll probably need to come in early and work till midnight, but we are confident you can
handle it. Oh, and we can't pay you extra because of budgetary constraints...
Get lost, jerk!
Hi, haven't I seen you somewhere before?
Get lost, jerk!
很显然,这段代码未经加工,但它确实展示了函数是如何允许你重用代码段的。
在上述脚本中我所做的第一件事情就是定义一个带有函数关键字的新函数。在该关键字后跟着函数的名称,在这个例子中就是myStandardResponse()函数。附着至该函数的所有编程代码接着置放在一对大括号内—且该程序代码可含有循环结构、条件语句、调用其他用户定义的函数或者其他PHP函数。
当然,定义函数只是问题的一半。如果你想让函数在任何情况下起作用,你需要对其进行“调用”。在PHP中,就像在一百万个其他语言中一样,函数调用是通过函数名称来调用函数而完成的,就像我在上述例子中所做的那样。调用用户定义的函数和调用PHP内置的函数(比如echo()或者explode())的方法是一致的。
下面是函数的典型格式:
function function_name (optional function arguments) {
statement 1...
statement 2...
.
.
.
statement n...
}
函数的两个参数
像你在前面章节所看到的函数在你每次调用的时候打印同样的值。尽管前六次这个看起来很有趣,但它在第七次的时候可以令人感到厌烦。为使得这些枯燥、没有智能的函数变得稍许精彩些,我们所需要做的就是让它们在每次被调用的时候返回不同的值。
输入参数(Enter argument)
参数通过在函数内使用一占位符来代表一个特定的变量而起作用。该变量的值在程序运行时从主程序提供给函数。因为函数每次调用的时候输入函数的变量值不同,所以结果也会不同。
想弄明白它是怎么工作的,请看下面的函数,该函数接受单一的参数然后在运算后将结果打印出来:
<?php // define a function function getCircumference($radius) { echo "Circumference of a circle with radius $radius is ".sprintf
("%4.2f", (2 * $radius * pi()))."<br />"; } // call a function with an argument getCircumference(10); // call the same function with another argument getCircumference(20); ?>
在这个例子中,当参数调用getCircumference()函数时,该参数值被赋给函数内的占位符变量$radius,然后就按照函数内部定义的代码行事。
向函数传递超过一个的参数也是可能的。这个可以采用逗号分割的参数列表来实现,就像下面例子显示的那样:
<?php
![]()
// define a function
function changeCase($str, $flag) {
/* check the flag variable and branch the code */
switch($flag) {
case 'U':
print strtoupper($str)."<br />";
break;
case 'L':
print strtolower($str)."<br />";
break;
default:
print $str."<br />";
break;
}
}
![]()
// call the function
changeCase("The cow jumped over the moon", "U");
changeCase("Hello Sam", "L");
![]()
?>
这里,根据第二个参数的值,函数内部的程序流程移动到适当的分支然后对第一个参数进行操作。
请注意,这里没有要求指定传递给函数的参数的数据类型。因为PHP是一种动态类型的语言,所以它自动识别变量类型然后对该变量类型进行适当的动作。
return语句
上述页面的函数只是简单的将它们的结果输出到屏幕上。但是如果你想让函数对结果做一些其他的事情会怎么样呢?那么在PHP中,你可以让函数返回一个值(诸如运算结果)给调用它的语句。这可以通过在函数内使用return语句来实现,如下所示:
<?php // define a function function getCircumference($radius) { // return value return (2 * $radius * pi()); } /* call a function with an argument and store the result in a variable */ $result = getCircumference(10); /* call the same function with another argument and print the return value */ print getCircumference(20); ?>
这里,处理传递给函数getCircumference()的参数,然后将结果返回给主程序,在主程序里面该结果在一变量中可以通过其他方式被捕捉、打印或处理。
你甚至可以在另外函数内部使用一个函数的结果,这一点在下面稍微对上面例子修改的代码中得到举例说明:
<?php
![]()
// define a function
function getCircumference($radius) {
// return value
return (2 * $radius * pi());
}
![]()
// print the return value after formatting it
print "The answer is ".sprintf("%4.2f", getCircumference(20));
![]()
?>
返回值不需要单独是数字或字符串:函数也可以像下面例子示范的那样容易的返回数组。还记得它们吗?
假定文件如下面所示那样:<?php /* define a function that can accept a list of email addresses */ function getUniqueDomains($list) { /* iterate over the list, split addresses and add domain part to another array */ $domains = array(); foreach ($list as $l) { $arr = explode("@", $l); $domains[] = trim($arr[1]); } // remove duplicates and return return array_unique($domains); } // read email addresses from a file into an array $fileContents = file("data.txt"); /* pass the file contents to the function and retrieve the result array */ $returnArray = getUniqueDomains($fileContents); // process the return array foreach ($returnArray as $d) { print "$d, "; } ?>
test@test.com
a@x.com
zooman@deeply.bored.org
b@x.com
guess.me@where.ami.net
testmore@test.com
而脚本的输出结果如下:
请注意,return语句结束了函数内部程序的执行。test.com, x.com, deeply.bored.org, where.ami.net,
顺序匹配(Marching Order)
参数传递给函数的顺序是重要的。下面的例子要求名称作为第一个参数来传递,且位置作为第二个参数来传递。
<?php // define a function function introduce($name, $place) { print "Hello, I am $name from $place"; } // call function introduce("Moonface", "The Faraway Tree"); ?>
下面是输出结果:
Hello, I am Moonface from The Faraway Tree
在这个例子中,如果你颠倒了参数传递给函数的顺序,那么你将会看到:
Hello, I am The Faraway Tree from Moonface
然后看看,如果你完全忘记了传递一个需要的参数,会发生什么呢:
为了避免这样的错误,PHP允许你在用户定义的函数中为所有的参数指定缺省值。如果函数少调用了一些参数,那么这些缺省值就会被使用。下面是例子:Warning: Missing argument 2 for introduce() in xx.php on line 3
Hello, I am Moonface from
<?php // define a function function introduce($name="John Doe", $place="London") { print "Hello, I am $name from $place"; } // call function introduce("Moonface"); ?>
在这个例子中,输出将会是:
Hello, I am Moonface from London
请注意,即使函数定义中需要两个参数,但函数被调用的时候只有一个参数。然而,因为函数内每个参数都有缺省值,那个缺少的参数值被参数的缺省值来代替,因而没有错误产生。
奇妙的可缩短的参数列表
上述页面中的所有例子都有一个共同点:函数定义的参数数目是固定的。然而,PHP 4.x通过使用func_num_args()和func_get_args()命令也支持变长参数列表。因为想要更好的名称,所以这些函数被称为“函数的函数”。当你学习下一例子的时候,请试着将精力集中在那些函数上,该例子解释了这些函数是如何使用的:
<?php // define a function function someFunc() { // get the arguments $args = func_get_args(); // print the arguments print "You sent me the following arguments:"; foreach ($args as $arg) { print " $arg "; } print "<br />"; } // call a function with different arguments someFunc("red", "green", "blue"); someFunc(1, "soap"); ?>
如果你比较狡黠,那么也许你会试着传递一个数组给函数someFunc(),然后发现它并没有显示数组元素而是简单的显示“Array”。你可以在函数内部通过对数组参数添加快速测试来修复这个问题,就像下列所重新编写的那样:
<?php // define a function function someFunc() { // get the number of arguments passed $numArgs = func_num_args(); // get the arguments $args = func_get_args(); // print the arguments print "You sent me the following arguments: "; for ($x = 0; $x < $numArgs; $x++) { print "<br />Argument $x: "; /* check if an array was passed and, if so, iterate and print contents */ if (is_array($args[$x])) { print " ARRAY "; foreach ($args[$x] as $index => $element) { print " $index => $element "; } } else { print " $args[$x] "; } } } // call a function with different arguments someFunc("red", "green", "blue", array(4,5), "yellow"); ?>
全局变量
现在,让我们来讨论一下函数内部所使用的变量以及它们与函数外部变量的关系。通常情况下,函数内部所使用的变量是“局部”变量(它意味着赋给该变量的值、以及对其所做的改变都单独地限于函数内部)。
考虑下面这个简单的例子:
<?php // define a variable in the main program $today = "Tuesday"; // define a function function getDay() { // define a variable inside the function $today = "Saturday"; // print the variable print "It is $today inside the function<br />"; } // call the function getDay(); // print the variable print "It is $today outside the function"; ?>
当你运行该脚本时,下面是你将会看到的结果:
It is Saturday inside the function
It is Tuesday outside the function
换言之,函数内部的变量和主程序中同名的变量是隔离的。因此函数内部的变量适于被称为“局部”变量,因为它们只存在于定义了它们的函数内部。
反过来也是真的,定义于函数内部的变量在外部不能被“看到”。为了详细说明,请看下面的例子和它的输出结果(或者没有输出):
<?php // define a function function getDay() { // define a variable inside the function $today = "Saturday"; } getDay(); print "Today is $today"; ?>
这里是程序的输出:
Today is
根据你在php.ini文件中设定的错误报告配置,你也许会看到下面的错误信息:
然而,我并没有说这种情况无法克服。为了让函数内部的变量从外部也可以访问(或者相反),你所需要做的是首先使用global关键字将它们声明为“全局性”的。Notice: Undefined variable: today in x1.php on line 10
下面是对早前的例子的改写,这次,将变量$today声明为全局性的:
<?php // define a variable in the main program $today = "Tuesday"; // define a function function getDay() { // make the variable global global $today; // define a variable inside the function $today = "Saturday"; // print the variable print "It is $today inside the function<br />"; } // print the variable print "It is $today before running the function<br />"; // call the function getDay(); // print the variable print "It is $today after running the function"; ?>
下面是其程序的输出:
It is Tuesday before running the function
It is Saturday inside the function
It is Saturday after running the function
所以,一旦变量被声明为全局性的,那么它在程序的全局范围内都是可访问的,而且它在函数的内部和外部均可以被操作。
PHP也提出了所谓的超全局变量(不管你是在函数内部还是外部,你都可以一直访问的变量)。你已经看到了一些这种特殊变量:$_SERVER、$_POST 和 $_GET变量都是超全局变量,这就是为什么你可以在函数内部访问像当前运行的脚本的名称或者表单值这样的信息。
超全局变量是个好东西,因为它们在你需要的任意时候都存在,而且你不需要跳出循环来使用存储在其中的数据。
检查引用
在没有提及“引用传递” 和“值传递”之间的区别的情况下,关于函数内部和外部的变量的任何讨论都是不完整的。到目前为止,你所看到的所有例子都涉及到通过“传值”方式(意味着变量的拷贝被传递给函数)来传递参数给函数,同时原变量保持不变。然而,PHP同样也允许你通过“引用”的方式来传递参数。意味着你传递原变量的一个引用而不是一个值给函数,同时让函数在引用上而不是拷贝上进行操作。
糊涂了吗?那么,用例子或许更容易理解。让我们以下面的代码开始:
<?php // create a variable $today = "Saturday"; // function to print the value of the variable function setDay($day) { $day = "Tuesday"; print "It is $day inside the function<br />"; } // call function setDay($today); // print the value of the variable print "It is $today outside the function"; ?>
你之前已经看到过而且你已经知道输出结果会是什么了:
这是因为当函数getDay()被调用的时候,它将值“Saturday”传递给函数(“值传递”)。原变量保持不变;只有它的内容被发送到函数。然后函数对其内容进行操作(修改和显示它们)。现在,让我们看看“引用传递”如何工作的:It is Tuesday inside the function
It is Saturday outside the function
请注意,函数定义中的参数前的符号&。该符号告诉PHP使用变量引用而不是变量的值。当这个引用被传递给函数时,函数内部的代码对该引用进行操作,且修改原变量(引用所指向的变量) 而不是变量拷贝的内容。如果你试着在函数外部检索原变量的值,那么它返回修改后的值:<?php 。
![]()
// create a variable
$today = "Saturday";
![]()
// function to print the value of the variable
function setDay(&$day) {
$day = "Tuesday";
print "It is $day inside the function<br />";
}
![]()
// call function
setDay($today);
![]()
// print the value of the variable
print "It is $today outside the function";
![]()
?>
现在你明白我为什么说不提及两种传递变量的方式而讨论变量是不完整的原因了吧。当然,这个也是全局关键字在函数内部所做的:使用引用以确保在函数内部对变量的修改也表现在外部。PHP手册上说得好 “当你将一个变量声明为全局变量$var时,实际上,你正在创建一个全局变量的引用”。.
It is Tuesday inside the function
It is Tuesday outside the function
接下来我们对本次教程做个总结。这次,通过学习如何将PHP代码的部分提炼为可重用的函数,你已经朝更好的软件设计迈进了一大步。你现在知道如何通过允许函数接受不同的参数以及如何从函数获得一个(或多个)返回值来为你的函数增加灵活性。最后,你也已经学习了一点关于PHP如何处理函数内部和外部的变量的知识。
在第七章中,我将会向你们展示如何将相关函数组织成类,也会告诉你们所有关于PHP5对象模型中非常酷的新特征。你绝对不想错过!
