【话说 PHP7(番外)】PHP 运行时错误

icy2003 程序 2020-10-12 11:49:50 21 0条

PHP 错误分为三种:语法错误、运行时错误、逻辑错误

38841-vsr9eq9o5h.png

  • 语法错误,有编辑器的提示下,在编写程序过程中基本不会遇到,此文略。
  • 逻辑错误就是写代码的人想法不正确,跟程序无关,此文略。
  • 运行时错误,简单理解就是,程序本身的语法没错,而是在执行时发生错误,通常一个运行时错误如果出现在线上环境,很可能需要遇到特定情况才能让错误重现,比较难排查,常见的有:分母为 0、数组索引错误等。

调试方法

线上环境一般会关闭错误提示,所以调试代码时,第一步就是要开启错误提示:

error_reporting(E_ALL);
ini_set('display_errors', '1');

接下来就是无脑 var_dump die 或者 file_put_contents 了……当然不是!虽然这两个也是最有效的笨办法

最常用的方法是使用 xdebug 调试,xdebug 的使用具体见:在 VsCode 下使用 Xdebug 调试 PHP

如何避免

  • 关闭错误提示,即 ini_set('display_errors', '0');(不要 error_reporting 这一行)
  • 使用 I::get 方法(终于进入正题了?)

I::get

I::get 最初的本意是为了去掉烦人的“数组索引报错”,毕竟这个报错是 PHP 里最最最最常见的,使用步骤如下:

composer 安装 icy2003/phpcomposer require icy2003/php ~1.0

use icy2003\php\I;,使用 I::get,具体代码如下:

<?php

use icy2003\php\I;

$array = [
    'name' => 'tom',
    'type' => 'cat',
];

include 'vendor/autoload.php';

echo I::get($array, 'color');

输出结果当然什么也没有,即使是开启了错误提示,也不会有任何输出。

意义

有些线上环境,即使关闭了错误提示,还是会看到报错,因为可能那个服务商并不提供修改这种配置的服务,关闭错误提示等于是无效操作。

这样做的意义就在于,当代码处于线上环境时,不会让用户看到代码报错提示,站在用户的角度上看,代码错误会让用户感到恐慌,而非预期的结果(比如这里什么也不输出),只会让用户觉得“是不是我网卡了?”,从体验上来说,就好了很多。即使真的真的真的被用户意识到“是你网站有问题”,也可以让客服以“请您尝试切换网络再重试”的借口,给开发争取紧急补救的时间,防止丢失用户(虽然听起来很扯,但是确实有效果)!

最重要的一点:我很懒

定义

如果 I::get 的作用如果只是这样,我就不会用前面那么长的篇幅来给它铺垫了,这是一个我测试了很多,虽然一些同事对此有争议,但是却让我很舒服的函数,它适用于 PHP 的八大数据类型!而它的含义就是最朴实无华的“get”,即“获取一个值”。

I::get 的定义:public static function get($mixed, $keyString, $defaultValue = null)

其中,mixed 支持八大类型,I::get 的行为会根据 mixed 的类型相应变化,defaultValue 为取值结果 null 时的默认值,下面按照 mixed 的类型来介绍 I::get 的行为:

以下所有行为可以混搭!

数组

对于数组,I::get 会以英文的句号(.)为分隔符,按照层级获取值,直到取值成功或者找不到(返回默认值)。如:

$array = [
    [
        'name' => 'tom',
        'type' => 'cat',
    ],
    [
        'name'=>'jerry',
        'type'=>'rat'
    ]
];

echo I::get($array, '0.name');

keyString0.name,表示“获取 $array 这个索引数组的第 0 个数组键为 name 的值”,结果就是 “tom”

字符串

函数内部实现为字符串截取,还是以 $array 为例子,I::get($array, '0.name.0') 的值为 “t”,也就是 “tom” 的第 0 位字符,因为在 0.name 之后,结果是字符串类型的 “tom” 了,于是后续的取值就变成了字符串截取

也就是说 I::get 逐层取值时,mixed 的数据类型会逐层变化,当然最简单的例子是 I::get('hello', 0),结果是 “h”

对象

对象的取值检测顺序为:get 方法,公有属性,各类 PHP 框架的魔术属性,例如:

class Test{
    public function getHeLlo(){
        return new Test2();
    }
}
class Test2{
    public $worl_d = [
        'name' => 'icy2003',
    ];
}
$test = new Test();
$res = I::get($test, 'he_llo.worl_d.name.1'); // $res 的值为 'c'

其中,被看作是方法时,下划线会被去掉,而属性则不会,上面的代码很好地说明了这一点

布尔值

等价于三元操作符,当然没有三元操作符好,毕竟多嵌套了一层函数,但 I::get 的意义就是在于“不报错和万能”

匿名函数

取值就是 mixed 位置匿名函数的值,keyStringdefaultValue 分别表示,当 mixed 值表示“真”和“假”时执行的操作,例子如下:

$i = 1;
// $res 值为 'a'; $i 值为 2;
$res = I::get(function () {
    return 'a';
}, function () use (&$i) {
    $i++;
}, function () use (&$i) {
    $i--;
});
$i = 1;
// $res 值为 ''; $i 值为 0;
$res = I::get(function () {
    return '';
}, function () use (&$i) {
    $i++;
}, function () use (&$i) {
    $i--;
});

这个行为看似很奇怪,我举个例子就很清楚了:尝试下载一个文件,下载成功以及失败时,后续执行一些操作

资源和 null

mixed 类型为资源和 null 时,只有 defaultValue 有效,目的是为了容错

参考

icy2003/php wiki:I::get

标签: 暂无

非特殊说明,本博所有文章均为博主原创。