[持续更新] PHP 的高级玩法

[持续更新] PHP 的高级玩法

技术 1573 字 / 3 分钟

为什么要写这个?

我是在高一的一个冬日偶然接触到 PHP 这门语言的。然后就开始一发不可收拾了——我用她来做了很多东西,不管是个人项目还是兼职时做的项目,能用上 PHP 的,我都尽量用上上。渐渐的,我开始想去学习更高级更深层次的东西。因此,我在高三的时候学习了 CodeIgniter 框架并且迷上了她。同时我也尝试过自己去写一个小的框架。

在真正做项目的时候,我才慢慢发现有很多常见的疑难杂症,是大部分 PHP 教程书上不会提到的。每次我都要花费大量的时间在网上搜索解决。

很多 PHP 书籍,都是从基础开始讲起的。一些生僻的、较为高级的用法,就被省略了。千篇一律的书籍,对于有一定开发经验的人来说,未必能有所收获。因此,我想自己整理一下,将自己遇到过的,学到的,一些 PHP 的高级玩法记录下来。

目录

  • 闭包函数
  • & 引用
  • for 循环参数可选
  • 静态变量的实质
  • 很实用的正则表达式
  • header 函数跳转的那些事

闭包函数

我之前去杭电的图书馆翻过不少 PHP 的书籍,提到了闭包函数的书有且仅有一本。并且那一本也只用了半面的篇幅就草草带过了。但是我是真的觉得这个挺重要的。 看一下我之前的那个“千古难题”:

class testClass{
	private $data = 12345;
	
	public function test(){
		function foo(){
			var_dump($this->data);
		}
		foo();
	}
}

$my = new testClass();
$my->test();

运行的话,PHP 会报错:Fatal error: Using $this when not in object context in. 就算像这样:

class testClass{
	private $data = 12345;
	
	public function test(){
		$mydata = $this->data;
		
		function foo(){
			global $mydata;
			var_dump($mydata);
		}
		foo();
	}
}

$my = new testClass();
$my->test();

在 foo() 函数中加上 global $this->data 声明一个全局变量也不行,输出的值是 NULL

所以怎样让 foo() 函数获取到类中的变量呢? 第一种方式,是将 $this->data 作为参数,放在 foo() 的括号中传入,但这实在太不优雅了。 另一种方式则是使用闭包:

class testClass{
private $data = 12345;
	
	public function test(){
		$mydata = $this->data;
		
		$foo = function() use ($mydata){
			var_dump($mydata);
		};
		
		$foo();
	}
}

$my = new testClass();
$my->test();

需要注意的是,在声明的 $foo 变量的大括号 } 中要加上分号。因为这并不是定义了一个函数,而是定义了一个变量。 闭包在 PHP 中的概念其实就是匿名函数,这个函数没有名称,并且被赋值给一个变量。匿名函数在 JavaScript 中经常会用到,因为很多方法的参数是一个函数,并且只在方法里面被调用一次。

& 引用

这个是很冷门的一个点。也是我在看 CodeIgniter 框架的源码时才遇见的。 举一个网上流传的经典例子:

function &test(){
	static $b = 0;
	$b = $b+1;
	return $b;
}

$a = test();   //输出 $b 的值为:1
$a = 5;
$a = test();     //输出 $b 的值为:2

$a = &test();  //输出 $b 的值为:3	*注意*
$a = 5;           //$b 的值变为了 5
$a = test();    //输出 $b 的值为:6	*注意*

注意这里第二次将 &test() 赋值给了 $a。第一次,我们是将 $b,给了 $a,仅仅是 1 这个值而已。 但第二次,我们是将 $b引用传给了 $a,也就是将 $b$a 绑定、关联在了一起。现在的 $a 就是 test() 函数中的静态变量 $b。因此,我们将 $a 变为 5 后,也就意味着 $b 也变成了 5。可能有些不好理解,嘛,可以自己写写感受一下。

for 循环参数可选

这应该是一个比较简单的小技巧了,很多语言也都支持这个特性。比如如下这个 for 循环:

for($i = 0; $i < 5; $i++){
	echo($i);
}

这里的变量 $i 是可选的,我们可以将其定义在循环体外面:

$i = 0;
for (;$i < 5; $i++){
	echo($i);
}

静态变量的实质

静态变量是定义在类中的,它与一般的变量不一样。一般的变量,实际上是属于类的实例的。每一个类的实例中的变量都不一样。而静态变量是属于类的,每一个实例中对静态变量的修改都将影响到全局。因为每一次修改都是修改的类中的那唯一一个静态变量。

header 函数跳转的那些事

在很多时候,我们如果需要跳转界面,一般都是会使用 header 函数: header('Location: https://wuhan5.cc/'); 这里是给页面加上了 HTTP 头,从而实现了 302 重定向,这一点在浏览器的开发者面板中可以看到。但调用 header 方法时很多人经常会犯一个错误,摘抄自 PHP 官方文档说明:

请注意 header() 必须在任何实际输出之前调用,不管是普通的 HTML 标签,还是文件或 PHP 输出的空行,空格。

如果在 header 方法前有任何内容的输出,常见于使用 echo``var_dump等方法而引起的。 CodeIgniter 框架中的 redirect 方法,就是使用 header 来实现页面跳转。不过他们同时还使用了 header('Refresh:0;url='.$uri); 来实现跳转。这点值得我们参考借鉴。

双引号的小技巧

PHP 中的单引号与双引号的区别相信很多人都了解——使用双引号包含的字符串会进行转义,而单引号的则不会。 因此,在需要拼凑的