飞机的 PHP 学习笔记二:函数

前言

最近在系统的学习 PHP ,参考的资料是《PHP编程》+ 官方文档(如果你有好的学习资料,欢迎推荐给我)。虽然这本《PHP编程》是基于 PHP5 的,但我笔记里的代码,全部在 PHP 7.2 的环境里测试过,是能够运行的。另,本笔记中只记录我模糊不清的知识。

定义函数

嵌套函数

PHP 中可以使用嵌套函数,但是其作用有限。内部函数不能自动取到外部函数的参数。除非外部函数被调用,否则内部函数无法被调用,另外外部函数代码被解析后,内部函数也不可以被调用。如:

function outer ($a)
{
    function inner ($b)
    {
        echo "there $b";
    }
    echo "$a, hello ";
    inner($a)
}
inner("reader"); // error! 因为外部函数还没有被调用
outer("well"); // well, hello there well
inner("reader"); // there reader
outer("well"); // error! 因为外部函数被调用时,内部函数被重定义了

嵌套函数,是一种有条件的全局函数,你可以控制在什么情况下提供这样的全局函数给用户使用。但也需要注意,过多的全局函数则会产生“全局污染”,所以,不可多用。

函数参数

按引用传递参数

按引用传递参数允许忽略普通的作用域规则,可以让函数直接访问和操作参数变量。使用 & 来标识:

function doubler(&$value)
{
    $value = $value << 1;
}

$a = 3;
doubler($a);

echo $a;

注意:只有变量(非常量)能被声明为按引用传递的参数。如将上面的例子改成: doubler(10) ,就会引起错误。

优点:按值传递时,PHP 必须复制值。特别时对大的字符串和对象来说,这将是一个昂贵的操作。按引用传递则不需要复制值。

缺点:操作难度相对较高。

可变参数

PHP 在用户自定义函数中支持可变数量的传输列表。

在 PHP 5.5 以及更早的版本中,PHP提供了三个函数用于检索在函数中所传递的参数。

  • func_get_args() ,返回一个提供给函数的所有参数的数组
  • func_num_args() ,返回提供给函数的参数数目
  • func_get_arg(argument_number) ,返回一个来自传输的特定参数
function countList()
{
  if (func_num_args() == 0) {
    return false;
  } else {
    $count = 0;
    for ($i = 0; $i < func_num_args(); $i++) {
      $count += func_get_arg($i);
    }
    return $count;
  }
}

echo countList(1, 5, 9); // 15

在 PHP 5.6 及以上的版本中,由 ... 语法实现。

访问变量参数中使用:

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

echo sum(1, 2, 3, 4)

传递过程中使用:

<?php
function add($a, $b) {
    return $a + $b;
}

echo add(...[1, 2])."\n"; // 3

$a = [1, 2];
echo add(...$a); // 3
?>

类型提示

当定义一个函数时,你可以要求一个参数是一个特定的类,或是继承自一个特定的接口的实例,一个数组或者一个回调。并在 PHP 7 中增加了对标量类型的支持:(bool, float, string, bool)。

// Scalar Type Hints
function printRecord(string $name, int $id, float $salary, bool $sex) {
    echo $sex ? "$name, $id, $salary, male.\n" : "$name, $id, $salary, female. \n";
}

printRecord("Tom", 101, 5650.00, TRUE); // Tom, 101, 5650, male.
printRecord("Suzy", 101, 5650.00, FALSE); // Suzy, 101, 5650, female.

在 PHP 7 中还增加了对函数返回值的的类型提示(这下彻底支持强类型了)

function mySuperFunction(): int
{
    return "5";
}

echo mySuperFunction(); // 5

返回值

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

function returnTwo()
{
    return array("Fred", 35);
}

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

$names = array("Fred", "Barney", "Wilma" ,"Betty");

function &findOne($n)
{
    global $names;

    return $names[$n];
}

$person =& findOne(1);
echo $person, $names[1]; // Barney Barney
$person = "Barnetta";
echo $person, $names[1]; // Barnetta Barnetta

在 PHP 7 中增加了对返回值类型声明的支持。

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

// Note that a float will be returned.
var_dump(sum(1, 2)); // float(3)

可变函数

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

function foo() {
    echo "In foo()<br />\n";
}

function bar($arg = '') {
    echo "In bar(); argument was '$arg'.<br />\n";
}

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

$func = 'foo';
$func();        // This calls foo()

$func = 'bar';
$func('test');  // This calls bar()

$func = 'echoit';
$func('test');  // This calls echoit()

如果没有为这个变量存在的函数,则代码执行时会产生一个运行错误。可以使用 function_exists() 来确定名为此变量的函数是否存在 $yesOrNo = function_exists(funcion_name);

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

匿名函数(闭包)

有些时候,一些函数是局部的和临时的。为了反映回调函数的短暂特性,允许临时创建一个没有指定名字的函数:匿名函数(或也称为闭包)。

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

$array = array("really long string here, body", "this", "middling length", "larger");
$sortOption = "random";

function sortNonrandom($array)
{
    $sortOption = false;

    usort($array, function($a, $b) use ($sortOption){
        if ($sortOption == "random"){
            // 通过随机返回( -1, 0, 1)进行随机排序
            return rand(0,2) - 1;
        }else{
            // 按照字符长度惊喜排序
            return strlen($a) - strlen($b);
        }
    });
    print_r($array);
}
print_r(sortNonrandom($array)); // 正常排序

PHP 文档中的一个例子,从父作用域继承变量:

$message = 'hello';

// 没有 "use"
$example = function () {
    var_dump($message);
};
echo $example(); // 输出如下
// Notice: Undefined variable: message in phpfile on line 6
// NULL

// 继承 $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"

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

感谢你看到了这里。如果文章有错误,请评论指正,谢谢!

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!