搞定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
相關文章
相關標籤/搜索