PHP是什么?
通常有人问,PHP是什么?如何介绍PHP呢?
面对这个简单的问题,一般我们都会简单得解答,PHP就是用来做网页的语言代码。
通常我们只是知道浏览网页,却不知道网页是由一个HTML( HyperText Markup Language )标签的纯文本文件展示出来的。那么问题又来到了, HTML又是什么?
简单点说,我们所浏览的网页都是HTML标记的超文本,借助web浏览器把其给解释执行出来的。
介绍PHP为什么又要扯到HTML呢?
因为,PHP是处理HTML代码的语言,执行效率比完全生成HTML标记的CGI要高许多。
所以对于PHP是什么,更专业的解释:PHP是一种运行在服务器端(SSI)、嵌入到HTML、的脚本语言。
服务器端语言:在网页传送到客户端前将之解释并执行完毕,简单来说,我们是看不到PHP代码的,我们看到的都是HTML解析之后的代码,而我们则是利用PHP操控HTML,使网页由静态转为动态效果。
嵌入到HTML:使用特殊的标识符嵌入到HTML代码中,提交网页之后在服务器中运行完成,生成HTML到嵌入的位置中返回给客户端,又客户端浏览器去解析展现出来。
脚本语言:一种直接可由txt上写程序,不需要编译,纯文本的语言,只需要软件解释就可以直接运行的程序。
关于PHP:PHP原始为Personal Home Page的缩写,后来改名为 “PHP: Hypertext Preprocessor”。它不是“Hypertext Preprocessor”的缩写,而是一种递归缩写。在1994年的时候是一个外国人,名叫Rasmus Lerdorf开发的,一开始是他为了制作自己的个人网站,使用了简单的用Perl语言编写的程序。后来又用C语言重新编写,包括可以访问数据库。他将这些程序和一些表单直译器整合起来,称为 PHP/FI。
为什么使用PHP?
语法结构简单。语法利用了 C、Java 和 Perl,易于学习。
开发效率高,执行网页速度比CGI、Perl、ASP更加快,而且占用资源少。
支持面向对象(OOP),并向下兼容,支持过程与面向对象两种风格的开发。
成本低,PHP是免费的。
支持很大范围的数据库。使用任何针对某数据库的扩展(例如 mysql)编写数据库支持的网页非常简单,使用抽象层如 PDO,或者通过 ODBC 扩展连接到任何支持 ODBC 标准的数据库。
实用性强,能运行于各种平台(Windows, Linux, Unix, Mac OS X 等等)上。
可实现模板化,实现程序逻辑与用户界面分离。
开发成本低,开发工具多。
应用广泛,全球互联网上有35%左右的网站为PHP驱动。
更新速度快,不断在优化。
说“PHP是世界上最好的语言”并非空穴来风,PHP的优点也不是一篇文章能介绍得完,现在也不必纠结于 PHP 神奇乎在哪里,对我们来说,PHP只是一个成熟的、流行的、容易入门的、开发网站的工具而已。了解PHP,知道一个情况就行了,完全没必要研究 Rasmus Lerdorf 是如何将 PHP 发展到现在这种独树一帜的过程嘛。
PHP能做什么?
PHP 能做任何事。PHP 主要是用于服务端的脚本程序,因此可以用 PHP 来完成任何其它的 CGI 程序能够完成的工作,例如收集表单数据,生成动态网页,或者发送/接收 Cookies。但 PHP 的功能远不局限于此。
PHP 脚本主要用于以下三个领域:
服务端脚本。这是 PHP 最传统,也是最主要的目标领域。开展这项工作需要具备以下三点:PHP 解析器(CGI 或者服务器模块)、web 服务器和 web 浏览器。需要在运行 web 服务器时,安装并配置 PHP,然后,可以用 web 浏览器来访问 PHP 程序的输出,即浏览服务端的 PHP 页面。如果只是实验 PHP 编程,所有的这些都可以运行在自己家里的电脑中。
命令行脚本。可以编写一段 PHP 脚本,并且不需要任何服务器或者浏览器来运行它。通过这种方式,仅仅只需要 PHP 解析器来执行。这种用法对于依赖 cron(Unix 或者 Linux 环境)或者 Task Scheduler(Windows 环境)的日常运行的脚本来说是理想的选择。这些脚本也可以用来处理简单的文本。
桌面(GUI)应用程序。对于有着图形界面的桌面应用程序来说,PHP 或许不是一种最好的语言,但是如果用户非常精通 PHP,并且希望在客户端应用程序中使用 PHP 的一些高级特性,可以利用 PHP-GTK 来编写这些程序。用这种方法,还可以编写跨平台的应用程序。PHP-GTK 是 PHP 的一个扩展,在通常发布的 PHP 包中并不包含它。
需要些什么?
使用 PHP ,首先要做的是搭建一个开发环境,新手可以使用PHP集成 环境安装包,可以快速安装和配置PHP环境。
如果想自己配置,欢迎参考本站教程:搭建最新版本开发环境(Apache2.4+MySQLxampp 5.7+php7.1.5);
PHP常用开发工具
可以编写 PHP 代码的工具很多,目前常见的有Dreamweaver、PHPedit、gPHPedit、Frontpage等,甚至使用记事本也能编写源代码(不建议)。开发工具不必过多研究,找一款适合自己的便可以开始进入PHP 的世界了。
关于PHP先介绍这么多,主要是如何使用PHP编写网页。
PHP 基本语法
1 PHP标记
我们知道,PHP是服务器端、嵌入到 HTML 、的脚本语言,那么服务器如何识别哪些是PHP代码呢?这就得依靠 PHP的标记符了。
默认地,PHP是以<?php … ?> 标识符为开始和结束的,初次之外,PHP7之前支持 4 种标记风格,默认情况下,
1.1 XML 风格:
<?php ... ?>
1.2 简短风格(short style):
<? ... ?>
1.3 SCRIPT 风格:
<script language = "php"> ... </script>
1.4 ASP 风格:
<% ... %>
注意: 简短风格 和 ASP 风格需要在 php.ini 配置文件中打开或关闭,打开方法是将选项 shor_open_tag 和 asp_tags 选项赋值 on 。如果你安装的是 PHP7 ,你会发现找不到 asp_tags 代码,那是因为 PHP7之后, 后两种标记风格(SCRIPT 风格、ASP 风格)被取消了,所以建议使用 XML 风格;还有如果文件内容是纯 PHP 代码,最好在文件末尾删除 PHP 结束标记。这可以避免在 PHP 结束标记之后万一意外加入了空格或者换行符,会导致 PHP 开始输出这些空白,而脚本中此时并无输出的意图。
2 注释
注释在写代码的过程中非常重要,好的注释能让你的代码读起来更轻松,而且有利于后期的维护工作。在服务器对代码编译时注释会被解析器忽略,因此注释不会影响到程序的执行。PHP支持三种注释方式:
2.1 单行注释(//c++风格)
// 这是单行注释
2.2 另一种单行注释注释(#shell 风格)
# 这也是单行注释
2.3 多行注释(/* c语言风格 */)
/* 这是多行注释块 它横跨了 多行 */
注意 : 单行注释不可以出现?> ,否则会被PHP编译器识别为PHP程序的结束符。这意味着在 // … ?> 或者 # … ?> 之后的 HTML 代码将被显示出来:?> 跳出了 PHP 模式并返回了 HTML 模式。
因为注释是写给人看的,使用注释规范也非常重要,总结一些常用注释规范:
2.4 文件头部介绍,
/**
*文件名简单介绍
*
*文件功能。
* @author alvin 作者
* @version 1.0 版本号
*/
2.5 类的注释,类名及介绍
/**
* 类的介绍
*
* 类的详细介绍(可选)
* @author 作者
* @version 版本号
* @date 2020-02-02
*/
2.6 函数的注释,函数的作用,参数介绍以及返回类型
/**
* 函数的含义说明
*
* @access public
* @param mixed $arg1 参数一的说明
* @param mixed $arg2 参数二的说明
* @param mixed $mixed 这是一个混合类型
* @return array 返回类型
*/
虽然也常有人鄙视代码需要注释这一回事,但是还是建议多些注释才是好习惯。
3 数据类型
PHP 支持 9 种原始数据类型。
四种标量类型:
boolean(布尔型),只有TRUE、FALSE两个值。
integer(整型),整数,默认取值(-2147483648,2147483648)。
float(浮点型,也称作 double),实数,大小为8个字节。
string(字符串),表示印号之间的字符,注意“双引号”和‘ 单引号’的区别。
三种复合类型:
array(数组),PHP变量的集合。
object(对象),一个类的实例。
callable(可调用),回调。
两种特殊类型:
resource(资源),表示PHP扩展资源,例如打开文件、数据库连接等。
NULL(无类型),仅有null这一个值。
注意:如果想查看某个表达式的值和类型,用 var_dump() 函数。如果只是想得到一个易读懂的类型的表达方式用于调试,用 gettype() 函数。要检验某个类型,不要用 gettype(),而用 is_type 函数。
关于is_type 函数:
is_array -- 检测变量是否是数组is_bool -- 检测变量是否是布尔型 is_callable -- 检测参数是否为合法的可调用结构 is_double -- is_float() 的别名is_float -- 检测变量是否是浮点型is_int -- 检测变量是否是整数is_integer -- is_int() 的别名is_long -- is_int() 的别名is_null -- 检测变量是否为 NULL is_numeric -- 检测变量是否为数字或数字字符串 is_object -- 检测变量是否是一个对象is_real -- is_float() 的别名is_resource -- 检测变量是否为资源类型 is_scalar -- 检测变量是否是一个标量 is_string -- 检测变量是否是字符串
如果要将一个变量强制转换为某类型,可以对其使用强制转换或者 settype() 函数。关于强制转换:
(int), (integer) - 转换为整形 integer
(bool), (boolean) - 转换为布尔类型 boolean
(float), (double), (real) - 转换为浮点型 float
(string) - 转换为字符串 string
(array) - 转换为数组 array
(object) - 转换为对象 object
(unset) - 转换为 NULL (PHP 5)
TRUE
或 FALSE
。两个都不区分大小写。 当转换为 boolean 时,以下值被认为是 FALSE
:
布尔值
FALSE
本身整型值 0(零)
浮点型值 0.0(零)
空字符串,以及字符串 “0”
不包括任何元素的数组
特殊类型 NULL(包括尚未赋值的变量)
从空标记生成的 SimpleXML 对象
所有其它值都被认为是 TRUE
。
······································································字符串、数组、对象都非常重要,后面需要专题研究····················································
4 变量
变量是存储信息的容器。虽然在 PHP 中并不需要初始化变量,但对变量进行初始化是个好习惯。isset() 语言结构可以用来检测一个变量是否已被初始化。
4.1 命名规则
变量以 $ 符号开头,其后是变量的名称
变量名称必须以字母或下划线开头
变量名称不能以数字开头
变量名称只能包含字母数字字符和下划线(A-z、0-9 以及 _)
变量名称对大小写敏感($y 与 $Y 是两个不同的变量)
Note: $this 是一个特殊的变量,它不能被赋值。
4.2 PHP变量作用域
local(局部),函数内部声明的变量拥有 LOCAL 作用域,只能在函数内部进行访问。
global(全局),函数之外声明的变量拥有 Global 作用域,只能在函数以外进行访问。
static(静态),静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。常用于递归函数中;
4.3 PHP 赋值
直接赋值:使用“=”直接赋值给变量;
传值赋值:当一个变量的值赋予另外一个变量时,改变其中一个变量的值,将不会影响到另外一个变量。
引用赋值:$a=”aa”; $b=&$a; 则改变$a的值,$b也变化。不同:存储结构是分开的,即使unset($a),$b还在(区分C语言)。
4.4 可变变量
可变变量是一种独特的变量,它允许动态的改变一个变量的名称,其工作原理是该变量的名称由另外一个变量的值来确定. 实现过程就是在变量的前面多加一个美元符号”$”
1
2
3
4
5
6
|
<?php
$a
=
"hello"
;
//定义一个普通变量
$
$a
=
"world"
;
//定义一个可变变量,$$a可以拆分为$和$a两部分,$a的值是hello,那么$$a就等于$hello
echo
"$a $hello"
;
//结果输出:hello world
echo
"$a ${$a}"
;
//结果输出:hello world
?>
|
普通变量$a的值时hello,可变变量
a的值时world.也就是说a的值时world.也就是说
a和$hello是等价的,值都为world。
4.5 预定义变量
PHP 提供了大量的预定义变量。这些变量集成在PHP内部开发环境中,无需定义直接拿来使用.
$_SERVER — 服务器和执行环境信息
$_GET — HTTP GET 变量
$_POST — HTTP POST 变量
$_FILES — HTTP 文件上传变量
$_REQUEST — HTTP Request 变量
$_SESSION — Session 变量
$_ENV — 环境变量
$_COOKIE — HTTP Cookies
$php_errormsg — 前一个错误信息
$HTTP_RAW_POST_DATA — 原生POST数据
$http_response_header — HTTP 响应头
$argc — 传递给脚本的参数数目
$argv — 传递给脚本的参数数组
5 常量
常量就是值永远不能改变的量,范围是全局的。
5.0 常量的命名
有效的常量名以字符或下划线开头;
常量前面没有美元符号($);
常量可以不用理会变量范围的规则而在任何地方定义和访问;
常量一旦定义就不能被重新定义或者取消定义;
常量的值只能是标量(boolean ,integer,float 和 string)
5.1 自定义常量:
define("NAME",$value,[TRUE]); //如果第三个参数为true,则不区分大小写,默认是区分大小写的; const CONSTANT = 'Hello World'; //在 PHP 5.3.0 后可以这样定义;
Note:
和使用 define() 来定义常量相反的是,使用 const 关键字定义常量必须处于最顶端的作用区域,因为用此方法是在编译时定义的。这就意味着不能在函数内,循环内以及 if 语句之内用 const 来定义常量。
5.2 获取常量的值
可以简单的通过指定其名字来取得常量的值,如果常量名是动态的,也可以用函数 constant() 来获取常量的值。
<?php const CONSTANT = 'Hello World'; echo CONSTANT; echo constant("CON"."STANT"); //constant的灵活之处在于可以拼接常量;
用 get_defined_constants() 可以获得所有已定义的常量列表。
5.3 判断常量值是否已经被定义
defined( name ) 函数检查某常量是否存在。若常量存在,则返回 true,否则返回 false。
5.4 预定义常量
__LINE__ //文件中的当前行号。
__FILE__ //文件的完整路径和文件名。如果用在被包含文件中,则返回被包含的文件名。
__DIR__ //文件所在的目录。等价于 dirname(__FILE__)。
__FUNCTION__ //返回该函数被定义时的名字(区分大小写)。
__CLASS__ //返回该类被定义时的名字(区分大小写)。
__TRAIT__ //返回 trait 被定义时的名字(区分大小写)。Trait 名包括其被声明的作用区域。
__METHOD__ //返回该方法被定义时的名字(区分大小写)。
__NAMESPACE__ //当前命名空间的名称(区分大小写)。
6 运算符
算数运算符:+ – * / % ++ –
连接运算符: .
赋值运算符: =, +=,-=,*=,/=,%=,.=
比较运算符:>,<,==,===,!= <>,!==
逻辑运算符: and,&& ; or,|| ; not,! ; xor(逻辑异或,两边不同返回TRUE,相同返回FALSE)
位运算符 : & ;|;^(异或,不同返回1);~(非运算符,1.0取反);<<左移,右边空出的补0;>>右移左边空出的补0
7 流程控制:
if 语句 – 如果指定条件为真,则执行代码
if…else 语句 – 如果条件为 true,则执行代码;如果条件为 false,则执行另一端代码
if…elseif….else 语句 – 选择若干段代码块之一来执行
switch 语句 – 使用 Switch 语句可以避免冗长的 if..elseif..else 代码块。
while – 只要指定条件为真,则循环代码块
do…while – 先执行一次代码块,然后只要指定条件为真则重复循环
for – 循环代码块指定次数
foreach – 遍历数组中的每个元素并循环代码块
7.1 if语句
if ($a > $b) { echo "a is greater than b"; }
7.2 if…else语句
if ($a > $b) { echo "a is greater than b"; } else { echo "a is NOT greater than b"; }
7.3 if…elseif….else语句
<?php if ($a > $b) { echo "a is bigger than b"; } elseif ($a == $b) { echo "a is equal to b"; } else { echo "a is smaller than b"; } ?>
相关:流程控制的替代语法
<?php if ($a == 5): echo "a equals 5"; echo "..."; elseif ($a == 6): echo "a equals 6"; echo "!!!"; else: echo "a is neither 5 nor 6"; endif; ?>
7.4 switch 语句
类似于具有同一个表达式的一系列 if 语句。下面使用两种不同方法实现同样的事,一个用一系列的 if 和 elseif 语句,另一个用 switch 语句:
<?php if ($i == 0) { echo "i equals 0"; } elseif ($i == 1) { echo "i equals 1"; } elseif ($i == 2) { echo "i equals 2"; } switch ($i) { case 0: echo "i equals 0"; break; case 1: echo "i equals 1"; break; case 2: echo "i equals 2"; break; } ?>
7.5 while 循环
$i = 1; while ($i <= 10): print $i; $i++; endwhile;
7.6 do…while循环
$i = 0; do { echo $i; } while ($i > 0);
注意 : while循环和do…while循环除了判断条件的位置不同外,还有一个区别就是do…while循环要在语句的尾部加上分号(;);
7.7 for循环语句
$people = Array(
Array('name' => 'Kalle', 'salt' => 856412),
Array('name' => 'Pierre', 'salt' => 215863)
);
for($i = 0; $i < count($people); ++$i)
{
$people[$i]['salt'] = rand(000000, 999999);
}
以上代码可能执行很慢,因为每次循环时都要计算一遍数组的长度。由于数组的长度始终不变,可以用一个中间变量来储存数组长度以优化而不是不停调用 count():
$people = Array(
Array('name' => 'Kalle', 'salt' => 856412),
Array('name' => 'Pierre', 'salt' => 215863)
);
for($i = 0, $size = count($people); $i < $size; ++$i)
{
$people[$i]['salt'] = rand(000000, 999999);
}
7.8 foreach 循环语句
foreach 语法结构提供了遍历数组的简单方式。foreach 仅能够应用于数组和对象,
有两种语法:
foreach (array_expression as $value) statement /* 将数组中的值遍历赋于$value */ foreach (array_expression as $key => $value) statement /* 将数组的键遍历赋于$key,将数组的值遍历赋予$value */
7.9 include 和 require
include() 每次执行文件都要进行读取,如果文件不存在,会给出一个 warning,但脚本会继续执行;
require() 文件只处理一次,这就意味着如果可能执行多次的代码,则使用require()效率比较高;
include_once() 与 include() 语句类似,唯一区别是如果该文件中的代码已经被包括了,则不会再次包括。
require_once() 与 require() 语句类似,唯一区别是如果该文件中的代码已经被包括了,则不会再次包括。
不同点:
对 include() 来说,在 include() 执行时文件每次都要进行读取和评估;如果文件不存在,会给出一个 warning,但脚本会继续执行;require()不能有条件的包含文件。使用require()语句包含的文件不能有返回值。
对 require() 来说,文件只处理一次(实际上,文件内容替换了 require() 语句。如果文件不存在,会报出一个 fatal error 脚本停止执行;
应用:
require 的使用方法如 require(“./inc.php”);通常放在PHP程式的最前面,PHP程式在执行前,就会先读入 require 所指定引入的档案,使它变成PHP 程式网页的一部份。
include 使用方法如 include(“./inc.php”);一般是放在流程控制的处理区段中。PHP程式网页在读到 include 的档案时,才将它读进来。这种方式,可以把程式执行时的流程简单化。
理解:require 相当于文件内容替换require()语句,只加载一次以后都在那里,当是不能重复加载;否则报错停止代码运行;include相当于运行一次脚本就加载一次文本内容,加载之后又需要重新加载,所以理论上require的效率更高,由此特性可区分报错级别与运用域;
7.10 其它语句:
continue 跳过当前循环,循环还在继续
break 跳出当前循环,循环终止;
exit 终止当前脚本,这行代码后边的代码不执行;
return 立即结束此函数的执行并将它的参数作为函数的值返回。
goto 操作符可以用来跳转到程序中的另一位置。通常的用法是用 goto 代替多层的 break。
8 函数
函数的执行原理:当封装完函数之后将其导入内存中,当调用函数时,找到对应的函数,执行对应的函数体,当碰到Return语句或者执行到函数尾部时,将控制权移交到函数的位置上,接着程序继续执行;
声明以关单 “function” 开头:
函数名能够以字母或下划线开头(而非数字)。
函数名对大小写不敏感。
可以通过参数向函数传递信息。参数类似变量。
多参数,要用逗号隔开。
可以使用默认参数。
return 语句使函数有返回值 。
8.1 函数基础:
8.1.1 一个函数可由以下的语法来定义:
<?php function foo($arg_1, $arg_2, /* ..., */ $arg_n) { echo "任何有效的 PHP 代码都有可能出现在函数内部,甚至包括其它函数和类定义。"; return $retval; } ?>
注意:函数名能够以字母或下划线开头,使用动词开始、驼峰命名法,函数名对大小写不敏感。
8.1.2 有条件的函数
<?php $makefoo = true; /* 不能在此处调用foo()函数, 因为它还不存在,但可以调用bar()函数。*/ bar(); if ($makefoo) { function foo() { echo "I don't exist until program execution reaches me.\n"; } } /* 现在可以安全调用函数 foo()了, 因为 $makefoo 值为真 */ if ($makefoo) foo(); function bar() { echo "I exist immediately upon program start.\n"; } ?>
注意:当一个函数是有条件被定义时,必须在调用函数之前定义。
8.1.3 函数中的函数
<?php function foo() { function bar() { echo "I don't exist until foo() is called.\n"; } } /* 现在还不能调用bar()函数,因为它还不存在 */ foo(); /* 现在可以调用bar()函数了,因为foo()函数 的执行使得bar()函数变为已定义的函数 */ bar(); ?>
函数不能重载或者重名,可以使用function_exists()检测函数是否存在;
8.1.4 函数的返回值
值通过使用可选的返回语句返回。只能返回 0 个或 1 个值,可以返回任何类型的值,所以需要返回多个值可以返回数组的形式,返回语句会立即中止函数的运行,并且将控制权交回调用该函数的代码行。如果省略了 return,则返回值为 NULL。
//返回不同类型的值,默认是返回NULL; if ( !function_exists('test') ) { function test() { return 123; return 12.3; return 'abc'; return null; return false; return array(123,12.3,'abc'); return new mysqli(); return md5('abc'); return fopen('1.php','r'); .... } }
8.1.5 函数的参数
函数可以有 0 个 或 多个 参数,通过参数列表可以传递信息到函数,即以逗号作为分隔符的表达式列表,参数可以从左向右求值,函数的参数可以是任意数据类型,可分为可选参数和必选参数,如果有可选参数和必选参数,必选参数一定在可选参数之前;
/* * @param number 行; * @param number 列; * @param string 默认内容; * @return string 表格 */ function createtable ( $rows,$cols,$content="xxx" ) { $table .= "<table border='1' width='80%' cellpadding='0' cellspacing='0'>"; for ( $i=1;$i<=$rows;$i++ ) { $table .= "<tr>"; for ( $j=1;$j<=$cols;$j++ ) { $table .= "<td>{$content}</td>"; } $table .= "</tr>"; } $table .= "</table>"; return $table; } echo table ( 3,5);
注意:默认参数和参数调用的顺序;
8.1.6 作用域
函数体内的变量称为局部变量,局部变量又分为动态变量和静态变量,动态变量函数执行完毕之后立即释放(不保存),静态变量是通过static关键字声明的变量,当第一次调用函数的时候相当与初始化静态变量,当函数执行完毕之后静态变量没有释放而是保存在静态内存中,当再次调用函数的时候首先从静态内存中取出变量的值继续执行。
函数体外的声明的变量或者在函数体内通过global关键字声明的变量称为全局变量。
//静态变量的栗子 $a = 2; $b = 3; function test (){ var_dump($a); //null ,函数体内不能使用全局变量的值; global $b; //声明了$b是全局变量 var_dump($b); //3 ,已经通过global声明使用的全局变量; $b = 5; static $i=1; echo $i; ++$i; } var_dump($i); //null,不能在函数体外调用局部变量的值; test(); //1 test(); //2 $i不再是1 echo $b; //5 ,在函数体内已经修改了$b的值; var_dump( $GLOBAL ); //打印全部的全局变量;
栗子比较混乱,为了节省文章长度;
8.1.7 函数的传值与传引用
传值:默认情况下,函数参数通过值传递(因而即使在函数内部改变参数的值,它并不会改变函数外部的值)。
//传值栗子 $str = "KiNg"; $cha_str = strtolower( $str ); echo $str ; //KiNg; echo $cha_str; //king; $str 还是原来的$str,没有被改变;
引用传值:如果希望允许函数修改它的参数值,必须通过引用传递参数。通过在参数前添加&符号,代表通过引用传递参数,在函数内部对其所做操作影响其本身;
//引用传值 $arr =array('a','b','c'); array_pop($arr); var_dump( $arr ); //$arr最后一个键值对已经被删除; //注意:只有传递变量才能使用传引用;
之前没有使用传引用是因为在传值之后直接使用传值的变量,相当于使用了改变之后的变量;
8.2 PHP特殊形式的函数
特殊函数形式主要有 5 种:可变函数、递归函数、匿名函数、回调函数、可变参数形式函数;
8.2.1 可变函数
PHP 支持可变函数的概念。这意味着如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数,并且尝试执行它。
<?php function test(){ echo "this is a test"; } test(); //正常方式; $func_name = "test"; $func_name(); //可变函数 get_defined_functions(); //得到所有函数; ?>
可变变量:一个可变变量获取了一个普通变量的值作为这个可变变量的变量名,都是等量代换的原则;
可变函数不能用于例如 echo,print,unset(),isset(),empty(),include,require 以及类似的语言结构。需要使用自己的包装函数来将这些结构用作可变函数。
8.2.2 回调函数
通俗解释:回调函数是在调用一个函数时将另外一个函数名称作为参数传递到函数体中,并在函数体内调用;
栗子:被传递函数无参数时
<?php //自定义一个函数作为参数 function study () { echo "studying..."; } //回调函数 function dowhat ( $func_name ) { echo "正在"; $func_name(); } //调用回调函数 dowhat("study"); //正在studying... echo call_user_func("dowhat","study"); //正在studying...
栗子:被传递函数有参数时
<?php //自定义一个函数作为参数 function study ( $parameter ) { echo $parameter." is studying..."; } //回调函数 function dowhat ( $func_name,$argument ) { $func_name( $argument ); } //调用回调函数 dowhat("study","Tong"); //Tong is studying... call_user_func("dowhat","study","Tong"); //Tong is studying... call_user_func_array("dowhat",array("study","Tong")); //Tong is studying...
栗子:被传递函数含有多个参数;
<?php //自定义函数作为参数 function add ( $x,$y ) { echo $x+$y; } //自定义函数作为参数 function reduce ( $x,$y ) { echo $x-$y; } //回调函数 function calculate ( $way,$x,$y ) { $way($x,$y); } 调用回调函数的方法 calculate( "add",5,4 ); //9 echo "<br />"; calculate( "reduce",5,4 ); //1 echo "<br />"; call_user_func("calculate","add",5,4); //9 echo "<br />"; call_user_func_array("calculate",array("reduce",5,4)); //1
在PHP系统函数中,回调函数有很多应用,常用的有 array_map()、array_walk()、array_fileter() 等;
8.2.3 匿名函数/闭包函数
匿名函数,也叫闭包函数,允许临时创建一个没有指定名称的函数,最经常用作回调函数参数的值,匿名函数也可以作为变量的值来使用;
栗子1:
<?php //创建匿名函数的方法; $func = function (){ return "this is a test"; }; //记得有个分号; var_dump( $func() ); //this is a test;
栗子2:
<?php //匿名函数的使用; $func_name = create_function("","echo 'this is a test';"); //注意格式规范 $func_name(); //this is a test;
栗子3 :
<?php
//匿名函数的使用;
$arr = [1,2,3,4,5];
var_dump($arr); //1,2,3,4,
var_dump(array_map( function($x){return $x*2;} ,$arr)); //2,4,6,8,10
call_user_func( function($name){echo "hello".$name;},"Tong" ); //hello Tong;
8.2.4 递归函数
如果函数A需要调用函数B,而发现函数B的代码实现与函数A完全相同,以此类推,此时就需要封装为递归函数,最基本的特点是函数自身调用自身,但必须在调用自身前有条件判断,否则无限无限调用下去。主要应用于PHP实现目录的遍历,目录的复制,删除非目录操作、无限极分类等;
<?php //递归函数; function test( $i ){ echo $i; if ( $i>=0 ) { $func_name =__FUNCTION__; $func_name($i-1); //相当于使用test($i-1); } echo $i; } test(2); //210-1-1012,要掌握解析为何是该结果哟!
__FUNCTION__的使用,返回的是函数的名称!尽量不要使用递归函数,很容易造成无限递归造成死循环;