搞定PHP面试 - 函数知识点整理

1、函数的定义

1. 函数的命名规则

函数名能够包含字母、数字、下划线,不能以数字开头。

function Func_1(){ } //合法
function func1(){ } //合法
function _func1(){ } //合法
function Func-1(){ } // 非法,不能包含 '-'
function 1_func(){ }// 非法,不能以数字开头
在此所说的字母是 a-z,A-Z,以及 ASCII 字符从 127 到 255(0x7f-0xff)。
所以实际上使用中文变量名也是合法的。
甚至使用中文的标点符号做为变量名都是合法的。
只是通常都不推荐这样用。
// 使用中文函数名和变量名
function 面积($长, $宽){ 
    return $长 * $宽;
}

echo 面积(2, 3); // 合法,输出 '6'

// 中文符号函数名
function ?。……(){ 
    return '中文符号';
}

echo ?。……(); // 合法,输出 '中文符号'

函数名不区分大小写

function Func(){ 
    return 'Func';
}

echo func(); // 输出 'Func'

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

2. 函数的特性

任何有效的 PHP 代码都有可能出如今函数内部,甚至包括其它函数和类定义。

函数中包含其余函数express

function foo()
{
  function bar()
  {
    echo "I don't exist until foo() is called.";
  }
}

/* 如今还不能调用bar()函数,由于它还不存在 */
foo();

/* 如今能够调用bar()函数了,由于foo()函数的执行使得bar()函数变为已定义的函数 */
bar(); // 输出 'I don't exist until foo() is called.'

函数中包含类编程

function foo()
{
  class Bar{
      public $a = 1;
  }
}

/* 如今还不能实例化 Bar 类,由于它还不存在 */
foo();

$bar = new Bar();

echo $bar->a; // 输出 '1'

PHP 中的全部函数和类都具备全局做用域,能够定义在一个函数以内而在以外调用,反之亦然。

示例见上面两个例子

函数无需在调用以前被定义,可是必须保证函数定义的代码可以被执行到

foo(); // 输出 'foo'

function foo()
{
  echo 'foo';
}

定义 foo() 函数的代码不会被执行数组

foo(); // PHP Fatal error:  Uncaught Error: Call to undefined function foo()

if (false) {
    function foo()
    {
      echo 'foo';
    }
}

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

function foo(){
    echo 0;
}

function foo() {
    echo 1;
} 
// PHP Fatal error:  Cannot redeclare foo() (previously declared

PHP 中能够调用递归函数

function recursion($a)
{
    if ($a <= 5) {
        echo "$a\n";
        recursion($a + 1);
    }
}
echo recursion(0);

输出闭包

0
1
2
3
4
5
要避免递归函数/方法调用超过 100-200 层,由于可能会使堆栈崩溃从而使当前脚本终止。 无限递归可视为编程错误。

递归次数过多app

function recursion($a)
{
    if ($a <= 300) {
        echo "$a\n";
        recursion($a + 1);
    }
}
echo recursion(0);
// PHP Fatal error:  Uncaught Error: Maximum function nesting level of '256' reached, aborting!

PHP 的函数支持参数默认值

function square($num = 0)
{
    echo $num * $num;
}
echo square(3), "\n";
echo square(), "\n";

输出函数

9
0

PHP 的函数支持可变数量的参数(PHP 5.6+)

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

echo sum(1);    // 输出 1
echo sum(1, 2);    // 输出 3
echo sum(1, 2, 3); // 输出6

2、函数的参数

经过参数列表能够传递信息到函数,多个参数之间以逗号做为分隔符。参数是从左向右求值的。ui

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

1. 经过值传递参数(默认)

默认状况下,函数参数经过值传递,即便在函数内部改变参数的值,它并不会改变函数外部的值。.net

function addition($num)
{
    $num++;
}

$num = 1;
addition($num); 

echo $num; // 输出 1

2. 经过引用传递参数

若是但愿函数能够修改传入的参数值,必须经过引用传递参数。

若是但愿函数的一个参数经过引用传递,能够在定义函数时该参数的前面加上符号 &

function addition(& $num)
{
    $num++;
}

$num = 1;
addition($num); 

echo $num; // 输出 2
使用引用传递参数,调用函数是只能传变量,不能直接传值。
function addition(& $num)
{
    $num++;
}

addition(1); // PHP Fatal error:  Only variables can be passed by reference

3. 参数默认值

函数能够定义 C++ 风格的标量参数默认值

function makecoffee($type = "cappuccino")
{
    return "Making a cup of $type.\n";
}
echo makecoffee(); // Making a cup of cappuccino.
echo makecoffee(null); // Making a cup of .
echo makecoffee("espresso"); // Making a cup of espresso.

PHP 还容许使用数组 array 和特殊类型 NULL 做为默认参数

function makecoffee($types = ["cappuccino"], $coffeeMaker = NULL)
{
    $device = is_null($coffeeMaker) ? "hands" : $coffeeMaker;
    return "Making a cup of ".join(", ", $types)." with $device.\n";
}
echo makecoffee(); // Making a cup of cappuccino with hands.
echo makecoffee(["cappuccino", "lavazza"], "teapot"); // Making a cup of cappuccino, lavazza with teapot.

默认值必须是常量表达式,不能是诸如变量,类成员,或者函数调用等。

默认参数必须放在任何非默认参数的右侧;不然,函数将不会按照预期的状况工做。

function makecoffee($type = "cappuccino", $coffeeMaker)
{
    return "Making a cup of {$type} with {$coffeeMaker}.";
}

echo makecoffee(null, 'Jack'); // Making a cup of  with Jack.

echo makecoffee('Jack'); // PHP Fatal error:  Uncaught ArgumentCountError: Too few arguments to function makecoffee(), 1 passed in XX and exactly 2 expected in XX

4. 类型声明

类型声明容许函数在调用时要求参数为特定类型。 若是给出的值类型不对,那么将会产生一个错误: 在PHP 5中,这将是一个可恢复的致命错误,而在PHP 7中将会抛出一个TypeError异常。

为了指定一个类型声明,类型应该加到参数名前。这个声明能够经过将参数的默认值设为NULL来实现容许传递NULL。

有效的类型声明

类型 描述 最小PHP版本
Class/interface name 该参数必须是给定类或接口的实例(instanceof)。 PHP 5.0.0
self 参数必须是当前方法所在类的实例(instanceof)。只能在类和实例方法上使用。 PHP 5.0.0
array 参数必须是数组(array) PHP 5.1.0
callable 参数必须是有效的 callable PHP 5.4.0
bool 参数必须是布尔值 PHP 7.0.0
float 参数必须是浮点数 PHP 7.0.0
int 参数必须是整数 PHP 7.0.0
string 参数必须是字符串 PHP 7.0.0

5. 严格类型

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

function toString(string $var)
{
    return $var;
}

var_dump(toString(1)); // string(1) "1"

能够基于每个文件开启严格模式。
在严格模式中,只有一个与类型声明彻底相符的变量才会被接受,不然将会抛出一个TypeError。 惟一的一个例外是能够将integer传给一个指望float的函数。

可使用 declare 语句和strict_types 声明来启用严格模式:启用严格模式同时也会影响返回值类型声明。

declare(strict_types=1);

function toString(string $var)
{
    return $var;
}

toString(1); // PHP Fatal error:  Uncaught TypeError: Argument 1 passed to toString() must be of the type string, integer given

将integer传给一个指望float的函数

declare(strict_types=1);

function toFloat(float $var)
{
    return $var;
}

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

严格类型仅用于标量类型声明,也正是由于如此,才须要PHP 7.0.0 或更新版本,由于标量类型声明也是在这个版本中添加的。

6. 可变数量的参数列表(PHP 5.5+)

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

... (in PHP 5.6+)

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

echo sum(1);    // 输出 1
echo sum(1, 2);    // 输出 3
echo sum(1, 2, 3); // 输出6

func_num_args()func_get_arg()func_get_args()(PHP 5.5)

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

echo sum(1);    // 输出 1
echo sum(1, 2);    // 输出 3
echo sum(1, 2, 3); // 输出6

3、函数返回值

1. 函数返回值的特性

值经过使用可选的返回语句(return)返回

能够返回包括数组和对象的任意类型。

返回语句会当即停止函数的运行,而且将控制权交回调用该函数的代码行。

函数不能返回多个值,但能够经过返回一个数组来获得相似的效果。

若是省略了 return,则返回值为 NULL。

function sum($a, $b) {
    $a + $b;
}

var_dump(sum(1, 2)); // NULL

2. return语句

若是在一个函数中调用 return 语句,将当即结束此函数的执行并将它的参数做为函数的值返回。
return 也会终止 eval() 语句或者脚本文件的执行。

$expression = 'echo "我在return以前"; return; echo "我在return以后";';

eval($expression); // 输出“我在return以前”

若是在全局范围中调用 return,则当前脚本文件停止运行。
若是在主脚本文件中调用 return,则脚本停止运行。
若是当前脚本文件是被 include 或者 require 的,则控制交回调用文件。此外,return 的值会被看成 include 或者 require 调用的返回值。

a.php

<?php
$b = require 'b.php';
$c = include 'c.php';

echo $b;
echo $c;

return;
echo '我在a.php return以后';

b.php

<?php
return "我是b.php\n";
echo '我在b.php return以后';

c.php

<?php
return "我是c.php\n";
echo '我在c.php return以后';

运行 a.php,输出结果为:

我是b.php
我是c.php

若是当前脚本文件是在 php.ini 中的配置选项 auto_prepend_file 或者 auto_append_file 所指定的,则此脚本文件停止运行。

Note: 注意既然 return 是语言结构而不是函数,所以其参数没有必要用括号将其括起来。一般都不用括号,实际上也应该不用,这样能够下降 PHP 的负担。

Note: 若是没有提供参数,则必定不能用括号,此时返回 NULL。若是调用 return 时加上了括号却又没有参数会致使解析错误。

Note: 当用引用返回值时永远不要使用括号,这样行不通。只能经过引用返回变量,而不是语句的结果。若是使用 return ($a); 时其实不是返回一个变量,而是表达式 ($a) 的值(固然,此时该值也正是 $a 的值)。

3. 函数的引用返回

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

function &myFunc()
{
    static $b = 10;
    return $b;
}

$a = myFunc();
$a = 100;
echo myFunc(); // 10;

$a = &myFunc();
$a = 100;
echo myFunc(); // 100;

4、可变函数

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

可变函数不能用于例如 echo,print,unset(),isset(),empty(),include,require 以及相似的语言结构。
须要使用本身的包装函数来将这些结构用做可变函数。

function foo() {
    return "I'm foo()\n";
}

// 使用 echo 的包装函数
function echoit($string)
{
    echo $string;
}

$func = 'foo';
echo $func();   // This calls foo(),输出“I'm foo()”

$func = 'echoit';
$func($func);  // This calls echoit(),输出“echoit”


$func = 'echo';

echo($func); // 输出“echo”

$func($func); // PHP Fatal error:  Uncaught Error: Call to undefined function echo()

能够用可变函数的语法来调用一个对象的方法

class Foo
{
    function variable()
    {
        $name = 'bar';
        $this->$name(); // This calls the Bar() method
    }

    function bar()
    {
        echo "This is Bar";
    }
}

$foo = new Foo();
$funcName = "variable";
$foo->$funcName();   // This calls $foo->variable(),输出“This is Bar”

当调用静态方法时,函数调用要比静态属性优先

class Foo
{
    static $variable = 'static property';
    static function variable()
    {
        echo 'Method Variable called';
    }
}

echo Foo::$variable; // 输出 'static property'.
$variable = "variable";
Foo::$variable();  // 调用 $foo->variable(),输出“Method Variable called”

能够调用存储在标量内的 callable(PHP 5.4+)

class Foo
{
    static function bar()
    {
        echo "bar\n";
    }

    function baz()
    {
        echo "baz\n";
    }
}

$func = ["Foo", "bar"];
$func(); // 输出 "bar"

$func = [new Foo, "baz"];
$func(); // 输出 "baz"

$func = "Foo::bar";
$func(); // 自 PHP 7.0.0 版本起会输出 "bar"; 在此以前的版本会引起致命错误

5、匿名函数

1. 匿名函数的特性

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

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

闭包函数也能够做为变量的值来使用。

PHP 会自动把此种表达式转换成内置类 Closure 的对象实例。把一个 closure 对象赋值给一个变量的方式与普通变量赋值的语法是同样的,最后也要加上分号。

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

$greet('World'); // Hello World
$greet('PHP'); // Hello PHP

闭包能够从父做用域中继承变量。

任何此类变量都应该用 use 语言结构传递进去。
PHP 7.1 起,不能传入此类变量: superglobals、 $this 或者和参数重名。

$message = 'hello';

// 没有 "use"
$example = function () {
    var_dump($message);
};
echo $example(); // PHP Notice:  Undefined variable: message

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

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

经过引用继承父做用域中的变量,能够将父做用域更改的值反映在函数调用中

$message = 'hello';

// 经过引用继承
$example = function () use (&$message) {
    var_dump($message);
};
echo $example(); // string(5) "hello"

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

闭包函数也能够接受常规参数

$message = 'world';

$example = function ($arg) use ($message) {
    var_dump($arg . ' ' . $message);
};
$example("hello"); // string(11) "hello world"

6、实例分析

例1

//声明函数swap,做为下面匿名函数的回调函数
function swap(&$x, &$y)
{
    $temp = $x;
    $x = $y;
    $y = $temp;

    return;
}

//call_user_func调用的回调函数
function add($a, $b)
{
    return $a + $b;
}

//匿名函数,即不声明函数名称而使用一个变量来代替函数声明
$fuc = function ($fucName) {
    $x = 1;
    $y = 2;
    //调用回调函数
    $fucName($x, $y);
    echo 'x=' . $x . ',y=' . $y, "\n";

    //与$fucName($x, $y)相同效果
    //这里没法调用swap方法,由于swap方法是对参数引用传值
    //call_user_func与call_user_func_array都没法调用引用传参形式的函数
    echo call_user_func('add', $x ,$y);
};

//调用 $fuc
$fuc('swap');

输出:

x=2,y=1
3

例2

$var1 = 5;
$var2 = 10;

function foo(&$my_var)
{
    global $var1;
    $var1 += 2;
    $var2 = 4;
    $my_var += 3;
    return $var2;
}

$my_var = 5;
echo foo($my_var). "\n";
echo $my_var. "\n";
echo $var1;
echo $var2;
$bar = 'foo';
$my_var = 10;
echo $bar($my_var). "\n";

第14行调用 foo() 方法

function foo(&$my_var)
{
    global $var1; // 5
    $var1 += 2; // 7
    $var2 = 4; // 4
    $my_var += 3; // 8
    return $var2; // 4
}

$my_var = 5;
echo foo($my_var). "\n"; // 4

第14行到第17行输出的值分别为:

echo foo($my_var). "\n"; // 4
echo $my_var. "\n"; // 8
echo $var1; // 7
echo $var2; // 10

第20行再次调用foo() 方法

function foo(&$my_var)
{
    global $var1; // 7
    $var1 += 2; // 9
    $var2 = 4; // 4
    $my_var += 3; // 13
    return $var2; // 4
}

$bar = 'foo';
$my_var = 10;
echo $bar($my_var). "\n"; // foo($my_var)  => 4
相关文章
相关标签/搜索