声明PHP脚本的方式
<?php ?>
最常用
<? ?>
短标记风格,需要在 php.ini 配置文件内 将 short_open_tag 设置为 ON ,然后重启
<% %>
ASP风格, 需要在 php.ini 配置文件内 将 asp_tag 设置为 ON ,然后重启
<script language="php"> </script>
: 脚本风格,基本用不到
<?= ?>
: 嵌入表达式
嵌入HTML
PHP和JSP类似,可以和HTML嵌套使用
<html>
<?php
// 定义变量
$name = "张三";
$age = 18;
?>
<head>
<?php //嵌入PHP代码 ?>
<title><?php echo '标题';?></title>
</head>
<?php //嵌入PHP代码 ?>
<body <?php echo 'bgcolor="#ccccccc"';?>>
<?php //嵌入PHP代码 ?>
大家好,我的名字是 <?php print($name); ?>
<br/>
<?php //嵌入PHP代码,表达式 ?>
我的年龄是: <?= $age; ?> 岁
<?php //嵌入PHP代码,IF判断 ?>
<?php if($age >= 18) {?>
<h1>我成年了</h1>
<?php } else{ ?>
<h1>我未成年</h1>
<?php } ?>
<?php //嵌入PHP代码,IF判断另一种写法 ?>
<?php if($age >= 18) :?>
<h1>我可以去网吧</h1>
<?php else: ?>
<h1>我还不能去网吧</h1>
<?php endif; ?>
</body>
</html>
PHP Web 的本质
其实 php 响应请求,就是一个输出IO流的过程; PHP解析器会将.php文件的内容解析执行后,将结果返回给客户端;
如下示例
<html>
<?php
// 定义变量
$name = "张三";
$age = 18;
?>
<head>
<?php //嵌入PHP代码 ?>
<title><?php echo '标题';?></title>
</head>
将会被解析成如下php代码
echo '<html>';
// 定义变量
$name = "张三";
$age = 18;
echo '<head>';
//嵌入PHP代码
echo '<title>';
echo '标题';
echo '</title>';
echo '</head>';
执行后,将结果返回给客户端
<html><head><title>标题</title></head>
所以.PHP可以和任何文本嵌套,本质就是 echo 输出
结尾空行的问题
在开发中会遇到尾行后换行的问题,如下代码,我们长时间的开发习惯,会在尾行多输出几个空行;
<?php
echo 'test';
?>
## 下面是开发习惯多出来的空行
会被解析成为如下代码
echo 'test';
echo 'n';
echo 'n';
如果客户端是严格解析,(如:JSON),客户端则会产生解析错误.
所以,开发中要注意到这一点,在 ?>
php文件结尾后,不要有多余的空行。
如果 一个 .php 文件中,全部都是 php代码,没有其他的文本,则可以忽略 ?>
,这样就不用担心结尾换行的习惯问题了;
# demo: exception.php
<?php
class MyException extends Exception
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
/* 省略 ?> ,下面的换行没事,不会被PHP解析 */
总结: ?>
结尾后的空白行 会被当做空字符串输出到客户端,可能导致客户端解析出现莫名其妙的错误。
所以,当客户端对空白字符串(空白行)敏感的时候(如API返回JSON的场景时),就应该注意空白行的问题。
或可以直接忽略结尾,忽略结尾的前提是 该PHP文件只有PHP的代码,不会和其他模板(HTML等)混合嵌套编程。
注释
# 行注释
/*多行注释*/
// 行注释
变量
PHP的变量名区分大小写,多个变量大小写不一样为不同的变量;
变量可以改变类型,和javascript等其他脚本语言类似;
$foo = 'Bob';
echo $foo; // 输出: Bob
$foo = 13 ;
echo $foo; // 输出: 13
$foo = new stdClass();
var_dump($foo);
默认值
虽然在 PHP 中并不强制需要先使用前,声明和初始化变量,但对变量进行初始化是个好习惯。
未初始化的变量具有其类型的默认值,下面列出每个类型的默认值:
Boolean: 默认值是 FALSE
整形和浮点型: 默认值是0
字符串型:默认值是 空字符串
数组变量 : 默认值是空数组
对象变量: 默认值是 new stdClass
// 输出NULL,没有被用作任何地方,无法推断出类型,所以为NULL
var_dump($unset_var);
// $unset_bool 变量在下面的表达式中被用作 Boolean ,所以PHP推断其为 Boolean 类型,但由于它没有声明和初始化,所以采用其默认值 FLASE
// 输出false
echo($unset_bool ? "true\n" : "false\n");
// $unset_str 变量在下面的表达式中被用作 String ,所以PHP推断其为 String 类型,但由于它没有声明和初始化,所以采用其默认值 空字符串
// 输出 abc
$unset_str .= 'abc';
var_dump($unset_str);
// $unset_int 变量在下面的表达式中被用作 int ,所以PHP推断其为 int 类型,但由于它没有声明和初始化,所以采用其默认值 0
// 输出 25
$unset_int += 25; // 0 + 25 => 25
var_dump($unset_int);
// $unset_int 变量在下面的表达式中被用作 float ,所以PHP推断其为 float 类型,但由于它没有声明和初始化,所以采用其默认值 0
// 输出 1.25
$unset_float += 1.25;
var_dump($unset_float);
// $unset_arr 变量在下面的表达式中被用作 Array ,所以PHP推断其为 Array 类型,但由于它没有声明和初始化,所以采用其默认值 空数组
$unset_arr[3] = "def"; // array() + array(3 => "def") => array(3 => "def")
var_dump($unset_arr);
// $unset_obj 变量在下面的表达式中被用作 object ,所以PHP推断其为 object 类型,但由于它没有声明和初始化,所以采用其默认值 new stdClass
$unset_obj->foo = 'bar';
var_dump($unset_obj); // 输出 object(stdClass)#1 (1) { ["foo"]=> string(3) "bar" }
建议一定要在变量使用前进行声明与初始化,使用未声明初始化的变量在较新的PHP版本会产生 **Notice** 通知
isset
isset() 检测变量是否声明,并且不是 NULL。
如果已经使用 unset() 释放了一个变量之后,它将不再是 isset()。若使用 isset() 测试一个被设置成 NULL 的变量,将返回 FALSE。
字符("\0")并不等同于 PHP 的 NULL
如果一次传入多个参数,那么 isset() 会根据根据参数,从左到右依次 isset(),全部都是 isset()则返回TRUE,如果发现非 isset() 则返回FALSE。
unset
清除释放一个变量;
// 销毁单个变量
unset ($foo);
// 销毁单个数组元素
unset ($bar['quux']);
// 销毁一个以上的变量
unset($foo1, $foo2, $foo3);
可变变量
可变变量名的作用: 动态的拼凑变量名,引用该变量;
简单的案例:
$abc = "abcdefg";
$one = "abc";
$abcdefg = "final";
echo $$one; // $one => 'abc' ; $$one = $abc = "abcdefg"
echo $$$one; // $one => 'abc' ; $$one ="abcdefg" ; $$$one = $abcdefg = 'final'
复杂的案例:
和数组、对象一起使用
class foo {
var $bar = 'I am bar.';
var $r = 'I am r.';
}
$foo = new foo();
$bar = 'bar';
$baz = array('foo', 'bar', 'baz', 'quux');
echo $foo->$bar . "\n"; // $foo -> $bar => $foo->bar => I am bar .
echo $foo->$baz[1] . "\n"; // $foo -> $baz[1] => $foo->bar => I am bar .
$start = 'b';
$end = 'ar';
echo $foo->{$start . $end} . "\n";// => $foo->bar => I am bar .
$arr = 'arr';
echo $foo->$arr[1] . "\n"; // => $foo->r => I am r .
echo $foo->{$arr}[1] . "\n"; // => ($foo->arr)[1] => I am B .
要将可变变量用于数组,必须解决一个模棱两可的问题。
这就是当写下 $$a[1]
时,
是想要 $a[1]
作为一个变量呢,
还是想要 $$a
作为一个变量,然后取出该变量中索引为 [1]
的值。
解决此问题的语法是,对第一种情况用 ${$a[1]}
,对第二种情况用 ${$a}[1]
。
$A = "zhangsan";
$arr = array('A', 'I am B.', 'I am C.');
echo ${$arr[0]}; // => $A => 输出 zhangsan
$name= 'arr';
echo ${$name}[0]; // => $arr[0] => 输出 A
变量的使用范围
PHP语言变量范围和其他的语言有很大的不同,请看下面的案例:
$a = 1; /* 全局变量 */
function test()
{
echo $a; /* 局部变量 */
}
test(); // 输出 “”,空字符串
这个脚本不会有任何输出,因为 echo 语句引用了一个局部版本的变量 $a,而且在这个范围内,它并没有被赋值。你可能注意到 PHP 的全局变量和 其他 语言有一点点不同,
在 其他 语言中,函数外部变量在函数中自动生效,可以被使用。除非被局部变量覆盖。
在PHP中,函数外部声明的变量为全局变量,函数内无法直接使用,需要使用 global
关键字,创建一个全局变量的引用,从而使用全局变量。
$a = 1; /* 全局变量 */
function test()
{
$x = 13 ;
if(true){
$b = 8;
}else{
$c = 9 ;
}
var_dump(get_defined_vars()); // x , b 已被定义
}
test();
$a = 1; /* 全局变量 */
function test()
{
$x = 13 ;
if(true){
$b = 8;
}else{
$c = 9 ;
}
var_dump(get_defined_vars()); // x , b 已被定义
}
test();
函数内的函数,访问函数中的变量,需要使用 use
才能获取到。
use 的语法必须和闭包一起使用
function test()
{
$x = 13 ;
$b = 13 ;
// 非闭包写法,就是单纯的内部函数,不支持和 use 使用
// function inner() use() {} // 这种事错的
function inner(){
global $x ;
echo $x ; // 输出空
}
inner(); // 输出空
// 闭包,使用上层函数的局部变量
$inner2 = function () use($x,$b) {
echo $x ;
echo $b ;
};
$inner2(); // 输出13 13
}
总结:
- 函数外的变量都是全局变量
- 函数中可以通过 global 关键字为全局变量创建引用,从而引用全局变量
- 可以使用 get_defined_vars() 函数获得当前作用域内声明的可用变量
include 作用域
其实 include 就是相当于代码拷贝
# index.php
<?php
include "other.php"; // 相当于把 oterh.php的代码拷过来,include 多次,相当于拷贝多次
echo $x ; // 输出13
# other.php
<?php
$x = 13;
全局变量 global 的本质
其实 global 后,就是对全局变量做了一个引用
$a = 1; /* 全局变量 */
function test()
{
global $a ; // 相当于给 $a 隐式的创建了一个引用
echo $a ;// 输出 1
}
如上代码 global $a
等同于 $a = & $a; (&$a) 表示取的是函数外面的 $a 的引用
所以, 如果在函数中,改变了 全局变量 的引用,则会和全局变量失去关联;(可以重新关联,看下例)
$a = 1; /* 全局变量 */
$b = 3 ; /* 全局变量 */
function test()
{
global $a ; // 相当于 隐式创建了一个引用 。 $a = &$a ;
$a = 'zhangsan' ; // 改变了值,也改变了类型
$x = 0 ;
global $b ;
$b = &$x ;
$b = 80 ;
}
test();
echo $a ; // 输出"zhangsan"
echo $b ; // 输出 3
为什么 $b
输出的是3而不是 80那? 看下面的过程讲解
global $b ; // 隐式创建了 $b 的引用
$b = &$x ; // 注意,这个时候 $b 被赋了新的引用,则 $b 不再为外部全局变量 b 的引用了
$b = 80 ; // 所以改变了 $b ,外部的全局变量 b 无变化
后面我们会详细的讲解引用,这里只需要知道,一旦被赋值新的引用则和之前的变量解除引用关系;
超全局变量
超全局变量就是系统提供的一些变量,这些变量都各自有他们的作用,后面我们也会挨个说明。超全局变量,在任何作用域范围都可以访问!
$GLOBALS
: 当前环境下的全局变量(Array)$_SERVER
: 当前环境上下文 SERVER 信息$_GET
$_POST
$_FILES
$_COOKIE
$_SESSION
$_REQUEST
$_ENV
前文中,我们使用了 global 关键字,引用全局变量,也可以使用 $GLOBALS
来完成同样的功能
$a = 1; /* 全局变量 */
function test()
{
echo $GLOBALS["a"]; // 输出1
}
预定义变量
预定义变量就是 PHP 帮助我们定义好的一些变量; 注意,这些变量并不是 超全局变量 , 所以在函数内使用得时候还是要使用 global 来创建引用才可以使用;
$php_errormsg
— 前一个错误信息$HTTP_RAW_POST_DATA
— 原生POST数据$http_response_header
— HTTP 响应头$argc
— 传递给脚本的参数数目$argv
— 传递给脚本的参数数组
注意! PHP 和 Java Web 不同, PHP的每一个访问都是开辟了新的进程,相当于运行了一个新的程序(其实本身就是CGi),所有的外界参数都得通过预定义变量传入;
静态变量
static 常被用在 函数中,配合递归使用。
function test()
{
static $x = 0 ; // 如果 $x 不存在则声明,存在则不会重新定义;
if($x > 5) {
unset($x); // 清理 static
return; // 终止递归
}
$x ++ ;
echo $x;
test();
}
// 输出 123456
常量
PHP中可以使用 define() 和 const 定义常量
define(常量名,常量值,是否大小写敏感)
可以使用 constant(常量名) 获得常量值
可以使用 get_defined_constants() 获得所有的常量
可以使用 defined() 判断变量是否定义
常量一旦定义,可以在脚本的任何地方使用
如果常量没有被定义而直接使用得话,会被转换成字符串,但是效率很低
echo 我的世界; // 输出 我的世界,没有这个常量,则转换为字符串
$arr = array("mykey" => 'myvalue');
echo $arr[mykey] ; // 输出 myvalue;
使用数组的时候,[key] 最好要带单引号或双引号,表示一个字符串,如果没有则会被当成常量,常量如果定义了,就会产生莫名其妙的难以查找的BUG; 上例中,可以正常输出的原因是因为,没有定义 mykey 的常量,转换为了字符串;
const 和 define 的区别
- const 经常和类定义配合使用
- const 只能在函数外最顶级作用域范围内声明
- define 可以在任何地方创建常量,只要能调用函数的地方都能创建
- const 只支持静态常量 而 define 支持表达式
- 常量可以在函数外声明,函数中使用
const BIT_5 = 1 << 5; // valid since PHP 5.6
define('BIT_5', 1 << 5); // 有效的valid
const u = 30 ;
var_dump(constant("u")); // 输出 30
魔术常量
这些常量比较特殊一些,值不可以更改;但是值会随着 场景不同变化; 如 __LINE__
会显示当前行号,会随着行的不同,显示的结果不同。 这些常量常用,但是很简单,这里就不多说了
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。