PHP基本语法及要点

386 阅读7分钟

PHP基本语法及要点

enable :可用

1. 脚本标识符
  • 标准风格: <?php code; ?> 推荐
    • 如果该脚本中只有php代码,可以省略掉后面的闭合标签,推荐省略。
  • 短标签风格: <? code; ?> 不推荐
    • 默认不支持该风格,需在php配置文件 php.ini 中特意开启才能解析 (即将 short_open_tag 设置为 On),否则会出现浏览器直接打印出php代码的现象。
  • asp风格:<% code; %> 不推荐
    • 默认不支持该风格,需在php配置文件 php.ini 中特意开启才能解析 (即将 asp_tags 设置为 On),否则会出现浏览器直接打印出php代码的现象。
  • script风格: 不推荐
2. 变量数据类型(8个)
  • 基本类型 int整型、float浮点型、boolean布尔型、string字符串型 中文字符为 宽字节 字符,一个中文占三个字节,可用 mb_strlen 函数查看宽字节字符的实际长度(记得第二个参数要指定)
  • 复合类型 array数值型、object对象型
  • 特殊类型 null空类型、resource资源类型
3. 变量名区分大小写
$a = 1;
$A = 2;
echo $a,$A; 
==> 12
  • 变量命名规则: 由数字[0-9]、字母[A-Za-z]、下划线[_] 组成,不能以数字开头。
  • 命名规范: 按语义命名,常用格式为 小驼峰法(userName) 或 下划线法(user_name)
4. 变量作用域类型
  • 局部作用域变量: 函数内部定义的变量,不能在函数外部使用。
  • 全局作用域变量: 函数外部定义的变量,不能在函数内部使用,除非使用 use 或者 global。
  • 超全局作用域变量:$_GET 常量 不受作用域限制,可以在任何地方访问, const 语句定义的常量访问时受命名空间的影响, define 函数定义的常量在访问时不受命名空间影响。
5. null false '' 0
$a;
$b = null;
$c = '';
$d = 0;
$e = false;
$f = 1;
$g = true;
$h = [];
$i = new stdClass();

var_dump($k, $a, $b, $c, $d, $e, $f, $g, $h, $i );
var_dump(isset($k), isset($a), isset($b), isset($c), isset($d), isset($e), isset($f), isset($g), isset($h), isset($i));
var_dump(is_null($k), is_null($a), is_null($b), is_null($c), is_null($d), is_null($e), is_null($f), is_null($g), is_null($h), is_null($i));
var_dump(empty($k), empty($a), empty($b), empty($c), empty($d), empty($e), empty($f), empty($g), empty($h), empty($i));
变量值var_dumpissetis_nullemptyif
$aNULL bool(false)bool(true)bool(true)bool(false)
$b = nullNULLbool(false)bool(true)bool(true)bool(false)
$c = ''string(0) ""bool(true)bool(false)bool(true)bool(false)
$d = 0int(0)bool(true)bool(false)bool(true)bool(false)
$e = falsebool(false)bool(true)bool(false)bool(true)bool(false)
$f = 1int(1)bool(true)bool(false)bool(false)bool(true)
$g = truebool(true)bool(true)bool(false)bool(false)bool(true)
$h = []array(0) { }bool(true)bool(false)bool(true)bool(false)
$i = new stdClass()object(stdClass)#1 (0) { }bool(true)bool(false)bool(false)bool(true)
总结:
  • isset 和 is_null 互反, empty 和 if 互反。
  • 只要变量 有值 且值不为 null 时,var_dump 是什么值就打印出什么值,isset 结果都为 true, is_null 反之都为 false;反之变量 未定义定义了但未赋值赋值为 null,此时 var_dump 打印值为 NULL,isset 结果都为 false, is_null 反之都为 true
  • 只要变量的值在语义上为 NULL(未定义、定义但为赋值、赋 null 值、赋 0 值、赋 bool 类型 false 值、赋空字符串值、赋空数组值),empty 结果都为 true, if 反之都为 false
6. isset
$a = $b = 0;
var_dump(isset($a), isset($c), isset($a, $b), isset($a, $c));

==> bool(true) bool(false) bool(true) bool(false)
总结:
  • isset 方法可以接收多个变量,只有当接收到的所有变量都存在且不为 NULL 时才返回 true
7. 定界符
$a = time();
$str = <<<_0djf
time : {$a}
_0djf;

$str1 = <<<"EOT"
time : {$a}
EOT;

$str2 = <<<'EOT'
time : {$a}
EOT;

var_dump($str, $str1, $str2);

==> string(17) "time : 1655712110"      
==> string(17) "time : 1655712110"
==> string(11) "time : {$a}"
总结:
  • 定界符有单引号和双引号模式,双引号模式会解析定界符类的变量,单引号模式会全部按字符串格式原样输出。
  • 定界符默认为双引号模式。
  • 定界符的命名规则同变量名的命名规则一致,但是得注意定界符必须得有闭合标签。
8. 文件引入
// 文件 a.json 不存在
echo 'start';
require 'a.json';
echo 'end';

==> start
==> Warning: require(a.json): failed to open stream: No such file or directory in D:\phpstudy_pro\WWW\lyl\tool\test.php on line 3
==> Fatal error: require(): Failed opening required 'a.json' (include_path='.;C:\php\pear') in D:\phpstudy_pro\WWW\lyl\tool\test.php on line 3

// 文件 a.json 不存在
echo 'start';
include 'a.json';
echo 'end';


==> start
==> Warning: include(a.json): failed to open stream: No such file or directory in D:\phpstudy_pro\WWW\lyl\tool\test.php on line 3
==> Warning: include(): Failed opening 'a.json' for inclusion (include_path='.;C:\php\pear') in D:\phpstudy_pro\WWW\lyl\tool\test.php on line 3
==> end
总结:
  • require、include、require_once、include_once。
  • 错误级别不一样,require、require_once 引入错误级别高(fatal error 致命错误),一旦引入报错程序会终止运行,include、include_once 引入错误级别低(warning 警告),引入报错程序仍会继续往下执行。
9. 形参中的点语法
  • 当函数(方法)所能接收到的形参数目不固定时,可以使用点语法。
    
        function sum(...$vars) {
            return array_sum($vars);
        }
        echo sum(1, 2);     // 3
        echo sum(1, 2, 3, 4, 5);    // 15
    
10. 函数返回值类型约束
  • 无返回值:  void
    
  • 返回值可为null:  ?             
      eg:   返回值为stringnull   ?string  
    
11. 语言结构
  • list
    
    $arr1 = ['1a', '1b'];
    list($a, $b) = $arr1;
    [$c, $d]    =   $arr1;
    $tmp = [$e, $f] =   $arr1;
    var_dump($a, $b); //string(2) "1a" string(2) "1b"
    var_dump($c, $d); //string(2) "1a" string(2) "1b"
    var_dump($e, $f); //string(2) "1a" string(2) "1b"
    var_dump($tmp);   //array(2) { [0]=> string(2) "1a" [1]=> string(2) "1b" }
    
    $arr2 = ['title' =>  '2a', 'time' =>  '2022-07-13'];
    list('title' => $title, 'time'  =>  $time) = $arr2;  // √
    var_dump($title, $time);    //string(1) "2a" string(10) "2022-07-13"
    
    $arr3 = ['3a', '3b', '3c'];
    list( , , $c3) = $arr3;
    var_dump($c3);  //string(2) "3c"
    
11. 打印
  • var_export 可以用来生成合法的php语法字符串。
    
    $arr2 = ['title' =>  '2a', 'time' =>  '2022-07-13'];
    var_export($arr2); //array ( 'title' => '2a', 'time' => '2022-07-13', )
    
    $data = var_export($arr2, true);
    echo $data; //array ( 'title' => '2a', 'time' => '2022-07-13', )
    
12. 日期、时间
  • getdate()
    
    var_dump(getdate()); 
    //array(11) { ["seconds"]=> int(12) ["minutes"]=> int(5) ["hours"]=> int(17) ["mday"]=> int(13) ["wday"]=> int(3) ["mon"]=> int(7) ["year"]=> int(2022) ["yday"]=> int(193) ["weekday"]=> string(9) "Wednesday" ["month"]=> string(4) "July" [0]=> int(1657703112) }
    
13. 文件上传
  • 修改 PHP.ini 配置文件可以定制上传机制,通过 phpinfo() 函数可以查看到 PHP.ini 文件所在位置(配置文件修改后记得重启PHP服务
配置说明
file_uploads是否允许上传文件,On 开启 Off 禁止上传
upload_tmp_dir文件上传过程中临时保存的目录,默认保存位置为 /tmp
upload_max_filesize允许上传的最大文件(单文件)大小,可以使用 K、M、G 单位如 2M
post_max_sizePHP 将接受的最大 POST 数据大小,包括上传文件、表单数据。所以 post_max_size 要大于 upload_max_filesize
max_file_uploads单个请求时,允许上传的最大文件数量,如果实际上传的文件数量大于这个配置项,多余的上传文件不会被接收
  • 文件上传到服务器后会先暂存到 upload_tmp_dir 指定的暂存文目录下(此时PHP可以在超全局数组 $_FILES 中找到该上传文件的详细信息),在请求结束后该暂存文件会被自动销毁,所以在文件未被销毁之前我们通过程序把暂存文件移到上传目录下即可完成简单上传功能

  • 前端表单选中图片确认时并没有真正将图片上传,点击表单提交时才会实行真正上传操作

  • 文件存储到服务器端时最好不用原文件名,因为用户很可能会上传同名文件,这样会导致上传文件被覆盖掉

  • 前端表单也可以限制上传文件的大小, MAX_FILE_SIZE 表单用来设置允许的上传大小,单位为字节。如果发生错误,错误码为 2

    <form action="2.php" method="post" enctype="multipart/form-data">
            <input type="hidden" name="MAX_FILE_SIZE" value="200"/>  /** 必须放在 input type = "file" 的表单项之前才起作用**/
            <input type="file" name="up">
            <button>提交</button>
    </form>
    
  • 超全局数组 $_FILES 参数说明

    编号选项说明
    1tmp_name临时文件名
    2name本地文件名
    3type文件MIME类型
    4error错误编号,只有为 0 时才说明上传成功
    5size文件大小(单位:字节))
  • 多图片上传

    <form action="../test.php" method="post" enctype="multipart/form-data">
        <input type="file" name="files[]">
        <input type="file" name="files[]">
        <button>提交</button>
    </form>
    
    <?php
        print_r($_FILES);
        
        Array(
            [files] => Array(
                [name] => Array(
                    [0] => 500fd9f9d72a60593819f9612e34349b033bbabb.jpg
                    [1] => bm.jpg
                )
                [type] => Array(
                    [0] => image/jpeg
                    [1] => image/jpeg
               )
               [tmp_name] => Array(
                    [0] => C:\Users\Administrator\AppData\Local\Temp\php95D9.tmp
                    [1] => C:\Users\Administrator\AppData\Local\Temp\php95DA.tmp
              )
              [error] => Array(
                    [0] => 0
                    [1] => 0
              )
              [size] => Array(
                    [0] => 346142
                    [1] => 25616
              )
          )
       )
    
  • 文件上传相关函数

    $htmlUpName 'up'//上传表单中上传input的name值
        $uploadStorageFullName ''//文件上传到服务器后实际存储的位置(包含文件名)
        if (is_uploaded_file($_FILES[$htmlUpName]['tmp_name'])) { //判断是否为合法的上传文件
            move_uploaded_file($_FILES[$htmlUpName]['tmp_name'], $uploadStorageFullName); //将上传文件从临时目录中移出到上传指定目录
        }
    
14. http无状态 会话控制 COOKIE SESSION
  • COOKIE 
    
    <?php
        setcookie('key', 'value'); //服务端PHP脚本向客户端浏览器种下 cookie
        //setcookie 函数的第三个参数为 int 类型,表示该cookie值过期时间(相对于Unix起始时间戳)
        setcookie('key', 'value', time() + 60); //设置一个过期时间为 60 s的 cookie,过期的 cookie 会被浏览器自动清理
        print_r($_COOKIE); //打印浏览器传过来的所有cookie值(数组)
    
    • 存储于浏览器客户端
    • 客户端在请求后端接口的时候会将 cookie 信息通过 http请求的 Request Headers(请求头) 传递给后端程序。
    • cookie 有两种状态:
      • session(会话) 状态:当未设置 cookie 过期时间或过期时间设置为 0 时 cookie 即为 session 状态,该状态下的cookie在浏览器关闭时会被清理掉。
      • 非session状态: 即设置了过期时间的 cookie,该状态的 cookie 不会因为浏览器关闭而被清理。
    • 子域名间 cookie 共享
      • setcookie 函数的第五个参数domain参数可用来设置cookie有效域名,设置成子域名(例如 'www.example.com'),会使 Cookie 对这个子域名和它的三级域名有效(例如 w2.www.example.com)。 要让 Cookie 对整个域名有效(包括它的全部子域名),只要设置成域名就可以了(这个例子里是 'example.com')。旧版浏览器仍然在使用废弃的 » RFC 2109, 需要一个前置的点 . 来匹配所有子域名。
  • SESSION
    
    • 存储于服务器端的会话数据
    • SESSION 会给客户端分配一把“钥匙(SESSION_ID)”,并且把这把钥匙存储在客户端的 cookie 中,客户端在访问服务端接口的时候会在请求头中带上这把“钥匙(SESSION_ID)”,服务端收到这把“钥匙(SESSION_ID)”后就会把其对应存储在服务端的会话数据提取出来。
    • SESSION 开启后,服务端接收浏览器客户端的 http 请求时,如果发现该请求没有携带 SESSION_ID 相关的 cookie 信息则会认为该客户端浏览器是第一次访问服务端,这时会在服务端生成一份 SESSION 文件用来保持此次会话数据信息并产生一个与之关联的唯一 SESSION_ID,并且在响应头中利用 Set_Cookie 指令在客户端浏览器将此 SESSION_ID 存储到客户端浏览器 cookie 中。 之后该客户端再次访问服务端时都会以 cookie 的形式带上已存储的 SESSION_ID,服务端根据该 SESSION_ID 去匹配查找对应的 SESSION 文件,来保持无状态 http 协议下的会话控制。
    • 服务端 SESSION 默认关闭,需要手动开启。
    • SESSION 开启函数 session_start(),session_start() 之前不能有任何输出。
    • session_destroy()函数会清除掉该会话数据并清除掉对应 SESSION 文件。
    • $_SESSION = [] 也可以清除掉该会话数据但不会清除 SESSION 文件,不过随后会被 PHP 的垃圾回收机制清除。
    • session_save_path() 指定 SESSION 文件在服务端存储的位置,该方法必须在 session_start() 之前使用才有效。
    • SESSION 有多种存储方式,默认为文件存储
    • 客户端保存 SESSION_ID 的 cookie 参数名为 PHPSESSID
    • 每一个客户端浏览器对应一个服务端 SESSION 文件,服务端每次生成的 SESSION 文件名都是唯一的,同一个浏览器在不携带 SESSION_ID 的状态下多次访问同一个服务器时每次获取到的 SESSION_ID 也是互不相同的。
    • 所以如果把浏览器客户端 cookie 中存储的 SESSION_ID 换成别人的 SESSION_ID 那么就能利用到别人的会话数据信息?
15. 面向对象
  • static
    
  • extends
    
  • trait
    
  • abstract
    
  • interface
    
  • 优先级
    
  • 访问控制
    
  • __get() 、 __set()、 __unset()、 __isset()、 __call()、 __callStatic()、 __toString()
    
16. 自动加载
  • __autoload() 方式: 该方式在 PHP7.2 版本已废弃
  • spl_autoload_register 方式
        //1.函数形式
        spl_autoload_register( function(string $class_name){ 
                require  $class_name . '.php';
            }
        );
        //2.或者以类方法的形式
        class BootStrap
        {
            public static function boot () {
                spl_autoload_register( [new self, 'autoload'] );
            }
            
            public function autoload( string $class_name ) {
                $file = str_replace('\\', '/', $class) . '.php';
                if ( !file_exists($file)) throw new Exception("类文件 {$file} 不存在~");
                require $file;
            }
        }
        
        BootStrap::boot();
            
    
  • composer 方式
    1. 命令行切换到根目录下,输入 composer init 指令生成一份 composer.json 文件
    2. 在生成的 composer.json 文件中增加 autoload 配置项(注意都用双引号 "")
    "autoload": {
        "psr-4": {
          "app\\""app",
        }
      }
    
    1. 命令行下输入 composer install 指令生成 vendor 文件夹,该文件夹下会包含一个 composer 目录和一个 autoload.php 文件

    2. 在入口文件中引入该 autoload.php 文件即可实现自动加载

      require 'vendor/autoload.php';

      ** psr-4 可以简单的理解为一种目录和命名空间的映射模式

      ** autoload 配置项可以配置任意文件的加载方式

      "autoload": {
          "psr-4": {
            "app\\""app",
            "serfoo\\""serfoo"
          },
          "psr-0": {
            """extend/"
          },
          "files": {
              "help.php",
              "app\utils\str.php"
          }
        }
      

      ** 当 composer.json 文件中的 autoload 配置项参数有修改时,需使用指令 composer update 让修改的配置生效

17. 错误与异常处理
  1. 错误处理
    • 优先级: 语法解析时错误 (Parse error) > 运行时错误 (fatal error: require不存在的文件)
    • error_reporting()
    • set_error_handler()
    • error_log()
    class Error {
        protected $debug;
    
        public function __construct( bool $debug = false ) {
            $this->debug = $debug;
        }
    
        public function boot() {
            error_reporting(0);
            set_error_handler( [$this, 'handle'], E_ALL | E_STRICT ); //使用该类中的 handle 方法处理 所有的 + 建议修改的 错误
        }
    
        /**
        * $code 错误类型标志
        * $error 错误具体信息
        * $file   错误所在文件
        * $line  错误所在行数
        **/
        public function handle( $code, $error, $file, $line) {
            $errorMsg = "{$error ($code) IN {$file} {$line}}";
            if ( $this->debug ) {//开启了调试模式,直接显示错误
                //这里可以针对不同级别的错误做不同的逻辑业务处理
                echo $errorMsg;
            } else {
                //未开启调试模式时可以将错误信息写入日志文件
                $file = 'logs/' . date('Y_m_d') . '.log';
                error_log( date(' [c] ') . $errorMsg . PHP_EOL, 3, $file ); // 3 表示用文件形式存储
            }
        } 
    }
    
    (new Error(true))->boot();
    
    
  2. 异常处理
    • set_exception_handle
    • $e->getFile()
    • $e->getCode()
    • $e->getLine()
    • $e->getMessage()
    • 异常优先级: Exception 应放在最后一个 catch 里捕获,因为所有自定义的异常都是 Exception 的子类,所以所有自定义异常也一定会被 Exception 捕获
    // bootstrap.php >>>
    <?php
    include "vendor/autoload.php";
    class Boot
    {
        public function init()
        {
            set_exception_handle([$this, 'exception']);
        }
    
        public function exception($e)
        {
            if ( method_exists($e, 'render') )
            {
                $e->render();
            } else {
                die($e);
            }
        }
    }
    
    (new Boot)->init();
    
    // Exceptions/ViewValidate.php >>> 
    <?php
    namespace App\Exceptions;
    use Exception;
    class ViewValidate extends Exception
    {
        public function render()
        {
            echo __METHOD__. $this->getMessage(); 
        }
    }
    
    // index.php >>>
    <?php
    include "bootstrap.php";
    throw new \App\Exceptions\ViewValidate('模板文件不存在'); //App\Exceptions\ViewValidate::render模板文件不存在
    

清单

  • header("Content-type:text/html;charset=utf8");
  • PHP glob函数
  • 所以如果把浏览器客户端 cookie 中存储的 SESSION_ID 换成别人的 SESSION_ID 那么就能利用到别人的会话数据信息?
  • PHP在代码运行之前会先检查解析所有代码的语法,这步会把代码中定义的 函数、类 加载到内存当中(所以函数的调用可以在申明之前,因为在语法检查分析的时候函数申明就已经被加载到内存中了),如果检查期间发现语法错误则会爆出 (Parse error: syntax error 解析错误:语法错误) 的错误且程序会直接终止退出。