PHP学习宝典-第八章(二)

网络整理 - 07-27
进价函式技巧

现在我们来看看函式的一些更神奇的属性,其中包括使用可变参数个数的方法、让函式能够修改传入变数的方法,以及让函式成为资料使用的法方。

这一节的内容是本章最具挑战性的一节,它只适合具有冒险精神、求知欲极强或经验丰富的程序设计师。

可变参数个数

在依据情况呼叫传入函式时,知道实际参数数量是很有用的,在PHP中有三种可能的方式处理,其中一个只能在PHP4使用:

1. 定义带有预设参数的函式,当函式在呼叫中遗漏任何参数时,它都会用预设值来代替,不会显示警告资讯。

2. 使用阵列参数存放这些值,由呼叫的程序码中负责包装这个阵列,函式本体必须适当地将其中的资料分离。

3. 使用PHP4中的可变参数函式(func_num_args()、func_get_arg()和 func_get_args())。

预设参数

为了定义带有预设参数的函式,只需把形式参数变成指定运算式即可。如果实际呼叫时的参数比定义时的形式参数少,PHP会拿形式参数和实际参数进行比对匹配,直到用完为止,然后就使用预设的指定来填满其余参数。

例如,下面的函式中的变数都有是用预设值定义的:

function tour_guide($city = “Gotham City”,

$desc = “vast metropolis”,

$how_many = “dozens”,

$of_what = “costumed villains”)

{

print(“$city is a $desc filled with

$how_many of $of_what.< BR >”);

}

tour_guide();

tour_guide(“Chicago”);

tour_guide(“Chicago”,“wonderful city”);

tour_guide(“Chicago”,“wonderful city”,

“teeming millions”);

tour_guide(“Chicago”,“wonderful city”,

“teeming millions”,

“gruff people with hearts of

gold and hard-luck stories to tell”);

浏览器会输出类似下面的结果,句中的换行符号由所用浏览器决定:

Gotham City is a great metropolis filled with dozens of costumed villains.

Chicago is a great metropolis filled with dozens of costumed villains.

Chicago is a wonderful city filled with dozens of costumed villains.

Chicago is a wonderful city filled with teeming millions of costumed villains.

Chicago is a wonderful city filled with teeming millions of gruff people whit hearts of gold and hard-luck stories to tell.

预设参数的主要限制是,实际参数到形式参数的匹配是由两者的依序比对确定的,先到先服务。因而不能乱用预设参数的设定,以致最后出一堆问题而不自知。

用阵列替代多个参数

如果对多个参数的弹性不怎么满意,可以使用阵列来当成沟通手段,这样可绕过整个参数计数问题。

下面的例子就是使用这个策略,另外还用了几个小技巧,如三元运算子(在第七章中介绍过)和关联阵列(在第六章中提不定期,在第十一章中才会全面讲解):

function tour_brochure($info_array)

{

$city =

IsSet ($info_array[ˋcityˊ])?

$info_array[ˋcityˊ]:“Gotham City”;

$desc =

IsSet ($info_array[ˋcityˊ])?

$info_array[ˋdescˊ]:“great metroprlis”;

$how_many =

IsSet ($info_array[ˋhow_manyˊ])?

$info_array[ˋhow_manyˊ]:“dozens”;

$of_what

IsSet ($info_array[ˋof_whatˊ])?

$info_array[ˋof_whatˊ]:“costumed villains”;

print(“$city is a $desc filled with

$how_many of $of_what.< BR >”);

}

这个函式检查将传入的阵列参数与特定字符串相隔的四种不同的值进行比较,使用三元条件运算子「?」,区域变数被指定为传入的值(如果已经被储存在阵列中),不然就是以预设值指定。现在,我们尝试用两个不同的阵列呼叫这个函式:

tur_brochure(array()); //空阵列

$tour_info =

aray(ˋcityˊ=>ˋCozumelˊ,

ˋdescˊ=>ˋdestination getawayˊ,

‘of_what’= >‘sandy beaches’);

tur_brochure($tour_info);

在这个例子中,我们首先用空阵列(对应于无参数)呼叫tour_brochure,然后用一个阵列来呼叫它,阵列中储存了四种可能关联值中的三种。其浏览器输出为:

Gotham City is a great metropolis filled with dozens of costumed villains.

Cozumel is a destination getaway filled with dozens of sandy beaches.

在两种情况下,「dozens」数量是预设的,因为两阵列都没有任何内容储存在「how_many」关联部份中。

在PHP4中使用多重参数

最后,PHP4提供了一些函式,可在函式本体内重新获得参数的个数和值,这些函式是:

fnc_num_args()不带参数,传回呼叫该函式时传入的参数个数。

fnc_get_arg()带一个整数参数n,传回该函式呼叫的第n个参数。参数计数从0开始。

fnc_get_args()不带参数,传回一个阵列,其中包含该函式呼叫的所有参数,阵列索引从0开始。

如果在函式本体外呼叫它们,这三个函式皆会丢出警告讯息,如果呼叫时所用的索引高于传入的最后的参数索引,func_get_arg()也会丢出警告。

如果使用者的函式会用到这些函式功能进行参数的解码,可以充分利用这里提到的关于函式呼叫,PHP不会因为实际参数比定义中的形式参数个数多而有所报怨。使用者可以定义不带参数的函式,然后使用这个函式来对比匹配任何实际传入的函式。

举例来说,请思考下面的两个函式实例,这些函式都传回一个被传入的参数阵列:

fnction args_as_array_1()

{

$arg_count = func_num_args();

$counter = 0;

$local_array = array();

wile($counter < $arg_count)

{

$local_array[$counter] =

fnc_get_arg($ary_counter);

$counter = $counter + 1;

}

rturn($local_array);

}

fnction args_as_array_2()

{

rtun(func_get_args());

}

第一个累赘的函式使用了func_get_arg()来撷取每个单独的参数,并使用func_num_args()的结果来给回圈定出界限,因此检索的参数不会比实际传入的多。每个参都被存放到阵列中,然后把这个阵列传回。把这样的参数包装起来实际上已经由func_get_arps()完成了,因此该函式的第二个版本就很简短了。

这里是另外一个例子,我们重写前面的tour_guide()函式,它使用了多个参数函式来替换预设参数:

fnction tour_guide_2()

{

$num_args=func_num_args();

$city = $num_args > 0 ?

fnc_get_arg(0):“Gotham City”;

$desc = $num_args >1 ?

$desc = $num_args > 1 ?

fnc_get_arg(1):“great metropolis”;

$how_many = $num_args > 2 ?

fnc_get_arg(2):“dozens”;

$of_what = $num_args > 3 ?

fnc_get_arg(3):“costumed villains”;

pint(“$city is a $desc filled with

$how_many of $of_what. < BR >”);

}

tur_guide2();

上面的程序码与预设参数形的程序码作用和效果相同,而且受到同样的限制。参数按照位置传入,因此没有办法用别的内容来替换「costumed villains」,只有用「Gotham City」为预设值。

按值呼叫(call-by-value)vs .按参引呼叫(call-by-reference)

PHP中使用者定义函式的预设动作是「按值呼叫(call-by-value传值呼叫)」,这意味着当把变数传递给函式呼叫时,PHP帮变数值制作一份副本并传给函式。因此,无论函式做什么,它都不能更改出现在函式呼叫中的实际变数。这种行为虽有好处,但也有坏处。当我们只想利用函式的传回值时,这当然是很好的方式,但如果修改传入的变数是实际目标,这样反而会有所妨碍。

下面会示范一个相当没有效率的减法例子的实作来按值呼叫的应用:

fnction my_subtract($numl,$num2)

{

i ($numl < $num2)

de(“Negative numbers are imaginary”);

$return_result = 0;

wile($numl >$num2)

{

$numl = $numl – 1;

$return_result = $return_result + 1;

}

rturn($return_result);

}

$first_op = 493;

$second_op = 355;

$result1 = my_subtract($first_op,$second_op);

pint(“result1 is $result1< BR >”);

$result2 = my_subtract($first_op,$second_op);

Print(“result2 is $result2< BR >”);

真好,我们看到了执行同样减法两次所得的结果会是一样:

rsult1 is 138

rsult2 is 138

即使my_subtract改变了它的形式参数$numl的值,还是会得到这样的结果,$numl变数只存放实际参数$first_op中值的副本而已,因此$first_op不会受到影响。

按照引呼叫(call-by-reference)

PHP提供了两种不同方式让函式在定义中,或者在函式呼叫中,更有能力来修改参数,也称为传址呼叫。

如果要定义一个直接对传入变数进行操作的函式,可以在定义中时在形式参数前面加一个「&」符号,如下所示:

fnction my_subtract_ref(&$numl,&$num2)

{

i($numl-<$num2)

de(“Negative numbers are imaginary”);

$return_result = 0;

wile($num1 >$num2)

{

$numl = $num1 – 1;

$return_result = $return_result + 1;

}

rturn($return_result);

}

$first_op = 493;

$second_op = 355;

$result1 = my _subtract_ref($first_op, $second_op);

pint(“result1 is $result1< BR >”);

$result2 = my_subtract_ref($first_op,$second_op);

pint(“result2 is $result2< BR >”);

现在,如果像前在那样执行同样的减法呼叫,会得到这样的输出:

rsult1 is 138

rsult1 is 0

这是因为形式参数$numl和实际参数$first_op所指的内容相同,修改一个就等于修改了另一个。