声明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>

image.png

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


}

总结:

  1. 函数外的变量都是全局变量
  2. 函数中可以通过 global 关键字为全局变量创建引用,从而引用全局变量
  3. 可以使用 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 的区别

  1. const 经常和类定义配合使用
  2. const 只能在函数外最顶级作用域范围内声明
  3. define 可以在任何地方创建常量,只要能调用函数的地方都能创建
  4. const 只支持静态常量 而 define 支持表达式
  5. 常量可以在函数外声明,函数中使用
const BIT_5 = 1 << 5;    // valid since PHP 5.6
define('BIT_5', 1 << 5); // 有效的valid
const  u = 30 ;
var_dump(constant("u"));  // 输出 30

魔术常量

image.png

这些常量比较特殊一些,值不可以更改;但是值会随着 场景不同变化; 如 __LINE__ 会显示当前行号,会随着行的不同,显示的结果不同。 这些常量常用,但是很简单,这里就不多说了


吴士岭
4 声望1 粉丝