PHP7语言结构——函数

文章目录

  • 内置函数
    • 阅读函数原型
  • 自定义函数
    • 函数的参数
    • 类型声明
      • 严格类型
    • 可变数量的参数列表
    • 返回值
      • 返回值类型声明
  • 可变函数
  • 匿名函数

内置函数

PHP提供了大量的内置函数,方便程序员直接使用,常见的内置函数包括数学函数、字符串函数、时间和日期函数等。

内置(内部)函数是PHP安装后就可以直接使用的,还有一些需要在安装时和特定的PHP扩展模块一起编译,才能使用。如,要使用image函数中的imagecreatetruecolor()函数,需要在编译PHP的时候加上GD的支持。或者,要使用mysql_connect()函数,需要在编译的时候加上MySQL支持。调用phpinfo()或者get_loaded_extensions()可以得知PHP加载了哪些扩展库。同时还应该注意,很多扩展库默认就是有效的。

要正确使用好内置函数,需要学会并认真阅读函数原型,确认一个函数接收什么样的参数,返回什么,以及函数是否直接作用于传递的参数。

阅读函数原型

函数定义告诉我们函数返回什么类型的值,接收什么参数,以strlen()定义为例:

strlen

(PHP4, PHP 5)
strlen -- 获取字符串长度

说明
int strlen( string str )

返回给定的字符串 string 的长度。

对函数定义的解释

组成部分 说明
strlen 函数名称
(PHP4, PHP5) strlen()在PHP4和PHP5的所有版本中都存在。
int 该函数返回的值的类型,这里为整型iteger。
(string str) 第一个参数,在该函数中名为string,且类型为string。

函数定义的一般形式:

返回类型	函数名	(参数类型 参数名)
returned type function name (parameter type parameter name)

自定义函数

函数定义语法:

function function_name(param1, param2, ...){
	statement;
}

其中function_name是函数名,param1、param2是参数,statement是函数的具体内容。

函数名和PHP钟的其他标识符命名规则相同。有效的函数名字以字母或下划线打头,后面跟字母,数字或下划线。可以用正则表达式:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*表示。

PHP保留所有以__开头的符号作为魔术符号。建议用户不要在PHP中创建以__打头的符号,除非是要使用有文档记载的魔术函数功能。

函数无需在调用之前被定义,除非函数是有条件被定义时,必须在调用函数之前定义:

$makefoo = true;

/* 不能在此处调用foo()函数,因为它还不存在,但是可以调用bar()函数。*/
bar();

if($makefoo) {
	function foo() {
		echo "我不存在,除非程序执行到这里.\n";
	}
}

/* 现在可以安全调用foo()函数了,因为$makefoo值为真*/
if ($makefoo) foo();

function bar() {
	echo "我从程序开始运行就存在.\n";
}
?>

还有一种情况下的函数是有条件定义的:


function foo() {
	function bar() {
		echo "我不存在,知道函数foo()被调用.\n";
	}
}
/* 现在还不能调用bar()函数,因为它还不存在 */
foo();
/* 现在可以调用bar()函数了,因为foo()函数的执行是的bar()函数变为已定义的函数 */
bar();
?>

PHP 中的所有函数和类都具有全局作用域,可以定义在一个函数之内而在之外调用,反之亦然。

PHP 不支持函数重载,也不可能取消定义或者重定义已声明的函数。

函数名是大小写无关的,不过在调用函数的时候,使用其在定义时相同的形式是个好习惯。

函数可以递归调用:


function recursion($a) {
	if ($a < 20) {
		echo "$a\n";
		recursion($a + 1);
	}
}
?>

所谓递归,就是一个函数不断的调用自身。但是要避免递归函数/方法调用超过100-200层,因为可能会使堆栈崩溃从而使当前脚本终止。无限递归可视为编程错误。

函数的参数

通过参数列表可以传递信息到函数,即以逗号作为分隔符的表达式列表。参数是从左向右求值的。

PHP 支持按值传递参数(默认),通过引用传递参数以及默认参数。也支持可变长度参数列表。

  1. 按值传递

    
    function sum($a, $b){	// 声明自定义函数
    	return $a + $b;		// 函数返回值
    }
    $a = 1;					// 声明全局变量
    $b = 3;
    echo sum($a, $b);		// 通过变量传递参数
    echo sum(12, 13);		// 直接传递参数值
    ?>
    
  2. 引用传递
    向函数传递参数引用,其实就是向函数传递变量引用。参数引用一定是变量引用,静态数值没有引用一说。
    默认情况下,函数参数通过值传递(因而即使在函数内部改变参数的值,它并不会改变函数外部的值)。如果希望允许函数修改它的参数值,必须通过引用传递参数。
    如果想要函数的一个参数总是通过引用传递,可以在函数定义中该参数的前面加上符号 &:

    
    // 声明自定义函数,参数前多了&,表示按引用传递
    function add_some_extra(&$string) {
    	// 改变形参的值,实参的值也会发生改变
    	$string .= 'and something extra.';
    }
    $str = 'This is a string, ';
    add_some_txtra($str);
    echo $str;		// 输出'This is a string, and something extra.'
    ?>
    
  3. 默认参数
    函数可以定义 C++ 风格的标量参数默认值,如下所示:

    
    function makecoffee($type="cappuccino") {
    	return "Making a cup of $type.\n";
    }
    echo makecoffee();		// 未指定参数$type,使用默认值
    echo makecoffee(null);  // $type值为null
    echo makecoffee("espresso");  // $type值为espresso
    ?>
    

    PHP还允许使用数组array和特殊类型NULL作为默认参数:

    function makeconffee($types=array("cappuccino"), $coffeeMaker = NULL) {
    	$device = is_null($coffeeMake)?"hands":$coffeeMaker;
    	return "Making a cup of ".join(",", $types)." with $device.\n";
    }
    echo makecoffee();
    echo makecoffee(array("cappuccino", "lavazza"), "teepot");
    ?>
    

    默认值必须是常量表达式,不能是变量、类成员,或者函数调用等。
    当使用默认参数时,任何默认参数必须放在任何非默认参数的右侧;否则,函数将不会按照预期的情况工作。

自PHP5起,传递引用的参数也可以有默认值。

类型声明

在PHP5中,类型声明也被称为类型提示。
类型声明允许函数在调用时要求参数为特定类型。如果给出的值类型不对,那么将会产生一个错误:在PHP5中,这将是一个可恢复的致命错误,而在PHP7中将会抛出一个TypeError异常。
为了制定一个类型声明,类型应该加在参数名前,这个声明可以通过将参数的默认值设为NULL来实现允许传递NULL。


class C {}
class D extends C {}
// this doesn't extend C
class E {}

function f(C $c) {				// 指定接收参数的类型为C
	echo get_class($c)."\n";
}

f(new C);
f(new D);
f(new E);	// 参数类型不是C,将出现错误
?>

以上代码将得到如下输出:

C D
Fatal error: Uncaught TypeError: Argument 1 passed to f() must be an instance of C, instance of E given, called in D:\phpstudy_pro\WWW\test.php on line 13 and defined in D:\phpstudy_pro\WWW\test.php:7 Stack trace: #0 D:\phpstudy_pro\WWW\test.php(13): f(Object(E)) #1 {main} thrown in D:\phpstudy_pro\WWW\test.php on line 7

严格类型

默认情况下,如果能做到的话,PHP将会强迫错误类型的值转为函数期望的标量类型。例如,一个函数的一个参数期望是string,但传入的是integer,最终函数得到的将会是一个string类型的值。

可以基于每一个文件开启严格模式。在严格模式中,只有一个与类型声明完全相符的变量才会被接受,否则将会抛出一个TypeError。唯一的一个例外是可以将integer传给一个期望float的函数。

使用declare语句和strict_types声明来启用严格模式:
declare(strict_types=1);
启用严格模式同时也会影响返回值类型声明.

严格类型适用于在启用严格模式的文件内的函数调用,而不是在那个文件内声明的函数。一个没有启用严格模式的文件内调用了一个在启用严格模式的文件中定义的函数,那么将会遵循调用者的偏好(弱类型),而这个值将会被转换。

严格类型仅用于标量类型声明,也正是因为如此,这需要PHP7.0.0 或更新版本,因为标量类型声明也是在那个版本中添加的。

可变数量的参数列表

PHP 在用户自定义函数中支持可变数量的参数列表。在PHP5.6及以上的版本中,由...语法实现;在PHP5.5及更早版本中,使用函数func_num_args()func_get_arg(),和func_get_args()


function sum(...$numbers) {
    $acc = 0;
    foreach ($numbers as $n) {
        $acc += $n;
    }
    return $acc;
}

echo sum(1, 2, 3, 4);
?> 

返回值

值通过使用可选的返回语句返回。可以返回包括数组和对象的任意类型。返回语句会立即中止函数的运行,并且将控制权交回调用该函数的代码行。

如果省略了 return,则返回值为 NULL。


function square($num)
{
    return $num * $num;
}
echo square(4);   // 输出 '16'.
?>

函数不能返回多个值,但可以通过返回一个数组来得到类似的效果。


function small_numbers()
{
    return array (0, 1, 2);
}
list ($zero, $one, $two) = small_numbers();
?>

从函数返回一个引用,必须在函数声明和指派返回值给一个变量时都使用引用运算符 &:


function &returns_reference()
{
    return $someref;
}

$newref =& returns_reference();
?> 

对于不需要引用的函数,可以做取消操作。取消引用使用unset()函数来完成,目的是断开变量名和变量内容之间的绑定,此时并没有销毁变量内容。

返回值类型声明

PHP7增加了对返回值类型声明的支持。同类型声明一样, 返回值类型声明将指定该函数返回值的类型。同样,返回值类型声明也与有效类型中可用的参数类型声明一致。

当覆盖一个父类方法时,子类方法的返回值类型声明必须与父类一致。如果父类方法没有定义返回类型,那么子类方法可以定义任意的返回值类型声明。

在默认的弱模式中,如果返回值与返回值的类型不一致,则会被强制转换为返回值声明的类型。在强模式中,返回值的类型必须正确,否则将会抛出一个TypeError异常.

可变函数

PHP支持可变函数的概念。这意味着如果一个变量名后有圆括号,PHP将寻找与变量的值同名的函数,并且尝试执行它。可变函数可以用来实现包括回调函数,函数表在内的一些用途。

可变函数不能用于例如echo,print,unset(),isset(),empty(),include,require 以及类似的语言结构。需要使用自己的包装函数来将这些结构用作可变函数。


function foo() {
	echo "进入foo()函数
\n"
; } function bar($arg='') { echo "进入bar()函数;传递的参数值为'$arg'.
\n"
; } // 使用echo的包装函数 function echoit($string){ echo $string; } $func = 'foo'; $func(); // 调用foo()函数 $func = 'bar'; $func('test'); // 调用bar()函数 $func = 'echoit'; $func('test'); //调用echoit()函数 ?>

也可以用可变函数的语法来调用一个对象的方法。


class Foo {
	function Variable() {
		$name = 'Bar';
		$this->$name();		// 调用类的Bar()方法
	}
	
	function Bar() {
		echo "This is Bar";
	}
}
$foo = new Foo();
$funcname = "Variable";
$foo->$funcname();		// 调用$foo->Variable()
?>

匿名函数

匿名函数(Anonymous functions),也叫闭包函数(closures),允许临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。

匿名函数目前是通过 Closure 类来实现的。


echo preg_replace_callback('~-([a-z])~',function($match){
	return strtoupper($match[1]);
}, 'hello-world');	//输出helloWorld
?>

闭包函数也可以作为变量的值来使用。PHP 会自动把此种表达式转换成内置类 Closure 的对象实例。把一个 closure 对象赋值给一个变量的方式与普通变量赋值的语法是一样的,最后也要加上分号:


$greet = function($name)
{
    printf("Hello %s\r\n", $name);
};

$greet('World');
$greet('PHP');
?> 

闭包可以从父作用域中继承变量。任何此类变量都应该用 use 语言结构传递进去。 PHP7.1起,不能传入此类变量: superglobals、 $this 或者和参数重名。
密码,,,,,,


$message = 'hello';

// 没有 "use"
$example = function () {
    var_dump($message);		
};
echo $example();			// 此次将抛出Undefined variable异常

// 继承 $message
$example = function () use ($message) {
    var_dump($message);
};
echo $example();		// 输出string(5) "hello"

// 继承变量的值是从定义函数时开始的,而不是从调用开始
$message = 'world';
echo $example();		// 输出string(5) "hello"

// 重置变量$message的值
$message = 'hello';

// 继承变量引用
$example = function () use (&$message) {
    var_dump($message);
};
echo $example();		// 输出string(5) "hello"

// 父作用域中更改的值反映在函数调用中
$message = 'world';
echo $example();		// 输出string(5) "world"

// 闭包还可以接受常规参数
$example = function ($arg) use ($message) {
    var_dump($arg . ' ' . $message);
};
$example("hello");		// 输出string(11) "hello world"
?>  

你可能感兴趣的:(PHP学习笔记)