0x01 匿名函数
匿名函数:顾名思义,他没有"名字"。相对于普通的定义函数需要按名调用来说,他有两种在调用方式:
1. 按值调用,由于匿名函数没有函数名,这个时候他相当于一条表达式,我们可以把它赋给一个变量,在需要使用的地方进行按值调用即可;
2. 作为回调函数被调用,顾名思义:回调即回头调用,此时的匿名函数作为其他函数的参数使用。这里使用匿名函数的好处是:每执行一次函数,回调函数才会被使用一次,所以没必要再耗费空间去定义一个专门的函数去处理回调事件,直接使用匿名函数即可。
注意:在php中不区分匿名函数和闭包。
以下是匿名函数的三种应用场景:
1. 匿名函数作为值来使用(注意,这里变量的值的类型是函数,也就是对象Object)
$val = function ($a, $b){ return $a * $b; }; // 注意这里有个; var_dump($val(2, 3)); // 6
这里有个需要注意的地方,匿名函数作为值来使用相当于赋值语句,所以务必记得php语句后不可或缺的' ; '。
2. 匿名函数作为回调参数使用
$arr = [1, 6, 3, 5, 2, 4]; usort($arr, function($a, $b){ return $a - $b; }); //后面的true表示不直接把结果输出到页面,而是存储在一个缓冲区当中 //这个时候如果要打印这个数组则可以把缓冲区中的内容保存到一个变量中,然后再打印这个变量; //或者直接用一个输出命令echo或输出函数输出。例:echo print_r($arr, true);才会有输出 //如果直接print_r($arr, true); 页面是没有输出的。 //<pre>格式化输出 echo '<pre>' . print_r($arr, true);
关于匿名函数作为回调参数使用需要注意的是:
(1)作为回调函数的调用过程类似于递归调用,简单点说就是:调用外部函数,然后外部函数将参数等必须的数值传入匿名函数中,最后外部函数在根据匿名函数的返回值做出相应的反应。
(2)使用匿名函数作为参数的外部函数必须要提前定义好才能调用,在示例中不需要定义的原因是:usort()是php自带的一个排序函数,他有两个参数,第一个是需要排序的数组,第二个是用户自定义的排序方式,该排序方式必须返回一个 <, =, > 0 的整数,然后usort()根据返回值调整数组元素的顺序。
3. 获取父作用域中的变量(常用于抽象开发)
$word = '一束光'; //可获取多个父作用域中的变量use($name1,$name2,...,$namen) $speak = function() use ($word) { return $word; }; echo $speak(); echo "<hr>"; function demo(){ $music = '最初的声音'; return function() use ($music){ return $music; }; } // $listen = demo(); //接收的返回值是一个匿名函数 // echo $listen(); //这里于按值调用一致 echo demo()(); //注意echo demo()();的写法在php5.6中会报错
注意点:获取父作用域的变量需要使用use($name1,$name2,...,$namen)来声明你所需要用到的变量;当多级函数的子函数是匿名函数时要注意调用的方法。
0x02 全局空间与命名空间
命名空间是一种封装事物的方法。每一个命名空间相当于一个文件夹,比如说一个文件夹下有一个名为demo.txt的文件,而另一个不同名的文件夹下也有一个名为demo.txt的文件,它们互不冲突,但当他们放在同一个文件夹下就会发生冲突。php代码也是一样的,在同一个php脚本中有两个同名函数会冲突;有两个同名变量时,后者会覆盖前者,而命名空间就是为了解决这些类/函数/常量之间的名字冲突问题。
全局空间也是命名空间,只不过他是特殊的“命名空间”。对于命名空间来说,全局空间相当于根目录,每一个定义的命名空间相当于根目录下的一个子文件夹。当一个php脚本没有定义命名空间,那么他默认是全局空间。
对于命名空间,有几点值得注意的地方:
1. 命名空间用namespace进行声明,命名规则与普通变量的命名规则一致(不能以数字开头)
2. 命名空间的声明必须放在php脚本中的第一行,以确保该脚本中的所有内容都保存在该命名空间下;
3. 当一个php脚本没有定义命名空间,那么他默认是全局空间
4. 每一个独立的php脚本中提倡只存在一个命名空间
5. 每个命名空间中的数据会进行整合,所以同名的命名空间内不能有重复的类/函数/常量
以下是命名空间的相关示例:
1. 第一种情况:关联脚本中只有一个有命名空间
demo2.php
<?php namespace _demo2; function sum($a, $b){ return $a*$b; } ?>
demo3.php
<?php include __DIR__ . '/demo2.php'; function sum($a, $b) { return $a + $b; } // echo namespace\sum(10, 20); echo sum(10, 20); //30 echo '<hr>'; // echo \_demo2\sum(10, 20); echo _demo2\sum(10, 20); //200
从上面的例子可以看到,demo2.php的命名空间为 _demo2 ,而demo3.php中没有命名空间,那么他就相当于是全局空间,在demo3.php中所执行的一切操作就相当于在全局空间中操作。
我们看到demo3.php中的第一条输出语句,他的前面没有加任何东西,所以他默认执行的是当前命名空间下的sum函数,他的完整写法是 echo namespace\sum(10, 20) ,用 namespa\ 标识它是当前命名空间下的函数,这样写的好处是当同一个php脚本引入多个命名空间时就不会导致混淆。
值得我们关注的是第二条输语句,他的完整写法应该是 echo \_demo2\sum(10, 20) ,最前面的反斜杠表示全局空间,_demo2\sum(10, 20) 表示命名空间_demo2下的sum函数。这涉及到了命名空间的定义:命名空间的定义使用的是相对路径,而根目录就是全局空间。例如:当我们要去每个文件时,我们首先要找到他的根目录,然后一级一级目录找下去,最终找到文件,即函数。但在本示例中,demo3.php的空间恰巧时全局空间,所以前面不用加反斜杠,如果不是全局空间这样写会报错。
2. 第一种情况:关联脚本中每个脚本各自有不同的命名空间
demo2.php
<?php namespace _demo2; function sum($a, $b){ return $a*$b; } ?>
demo3.php
<?php function sum($a, $b) { return $a + $b; }
demo4.php
<?php namespace _demo4; include __DIR__ . '/demo2.php'; include __DIR__ . '/demo3.php'; function sum($a, $b) { return $b / $a; } // namespace\ 指明后面调用的函数是当前空间中的函数 echo namespace\sum(10, 20); //2 echo '<hr>'; // 第一个 \ 标识全局空间,_demo2\sum(10, 20)指的是 _demo2 这个命名空间下的sum函数 echo \_demo2\sum(10, 20); //200 echo '<hr>'; // 函数前只有一个 \ 表示的是全局空间下的sum函数 echo \sum(10, 20); //30
3. 第三种情况:一个php脚本里有多个命名空间(包括全局空间),不推荐使用这种方式
<?php namespace one{ class test{ //... } } namespace two{ class test{ //... } } namespace three{ class test{ //... } } //匿名空间,即全局空间 namespace { class test{ //... } } ?>
当一个脚本中有多个命名空间时,每个命名空间用{ }把自己空间内的内容括起来即可。
0x03 类与对象
类:使用class来进行声明,类中有属性和方法
对象:类的实例化,使用关键字new来创建,创建出来的对象拥有类中的所有属性与方法;每一次实例化都是不同的对象。
简单点来说,类保存是一类事物的描述和行为的盒子,它本身是没有意义的。当我们使用new来创建该类的一个对象,就相当于为这个类找到了一个承载体,这个承载体就不是一个盒子了,而是一个拥有盒子中的所有东西的事物。例如,类是一个瓶子,这个类的对象是一个蓝色的、圆柱体的,可以用来装水的瓶子。
以下是类与对象的使用方式:
<?php namespace _demo6; class People{ //属性 //public为限制符,表示允许所有人访问 public $name = '小明'; public $desc = '小学生'; } // 1.类的实例化 $obj = new People(); // 2.使用对象访问类中的成员 echo $obj->name . '是' . $obj->desc;
1. 首先要创建一个类,类中有属性与方法(此处只展示属性)
2. 类的实例化,new一个对象(类的承载体)
3. 使用对象访问类中的成员,对象->类成员
0x04 总结
1. 匿名函数有三个应用场景:
(1)匿名函数作为值来使用(注意,这里变量的值的类型是函数,也就是对象Object)
(2)匿名函数作为回调参数使用
(3)获取父作用域中的变量(常用于抽象开发)
2. 对于命名空间来说:
(1)命名空间用namespace进行声明,命名规则与普通变量的命名规则一致(不能以数字开头)
(2)命名空间的声明必须放在php脚本中的第一行,以确保该脚本中的所有内容都保存在该命名空间下;
(3) 当一个php脚本没有定义命名空间,那么他默认是全局空间
(4)每一个独立的php脚本中提倡只存在一个命名空间
(5)每个命名空间中的数据会进行整合,所以同名的命名空间内不能有重复的类/函数/常量
(6)应用对象:类/函数/常量/接口(特殊的类)
(7)适用场景:用于解决类/函数/常量同名的问题;为很长的标识符名称创建一个简短的名称,提高源代码的可读性。