弱类型下的参数类型检查


昨天看到一个项目,特别好奇的看了一眼,顿觉世界人民还是智慧满天下的。

大家可能都知道,php 是弱类型的,那么就意味着有各种可能性,bug 能在代码中游离,不顾一切。

好了,段子说完了,我们开始说正题。

如果要做到参数检查,无非两点

  1. 语言本身支持
  2. 写校验

对于第一点可以选择 hacklang,不缀述了。本文围绕第二点,可能看到这儿你会觉得我偏你感情,校验谁不会,但客官先别急。

我以前也是如同你这般,检验参数谁不会的态度走了这么久…但当我看到昨天那个项目的时候,有必要写一篇出来。

昨天看到的项目的校验是这么写的

<?php

function foo($a, $b) {
  Argument::i()
    ->test(1, 'string')
    ->test(2, 'number');
}

而通常我们写是这么写的

<?php

function foo($a, $b) {
    if (!is_string($a) || !is_numeric($b)) {
        throw new ArgumentInvalidException('xxx');
    }
}

摔桌子……

一个是完全有规律有节奏的校验,一个是没有共性 case by case 的校验。

最近也是对数据的校验产生了浓厚的兴趣,原因无他,因为没有一个能把这个事情干漂亮的。

看到这儿,大家可能也想知道是如何做的?

在整个 PHP 体系里面,奇技淫巧数不胜数,当然从侧面讲是“高级特性”。要想做到上面写到的这块代码描述的情况,也不是什么难事儿。咋们可以幻想一下,实现此类功能,应该如何做;

  • 首先得获取到调用参数的运行时变量值
  • 然后给定规则校验这个值是否 OK

可以看到,就如第一段代码描述的,感觉只有设定规则,并没有去获取函数参数值。这块就让我百思不得姐了;

<?php


function foo() {
    var_dump(debug_backtrace());
}

foo(1, 2, 'test');

其输出

array(1) {
  [0]=>
  array(4) {
    ["file"]=>
    string(31) "/Users/shouding/Downloads/t.php"
    ["line"]=>
    int(8)
    ["function"]=>
    string(3) "foo"
    ["args"]=>
    array(3) {
      [0]=>
      int(1)
      [1]=>
      int(2)
      [2]=>
      string(4) "test"
    }
  }
}

居然用了 debug_backtrace 函数,虽然这样能拿到参数,但我想性能损耗也是比较大的。

可能你会突然说,我操,原来用来这个东西,但其实我们很少用到这些,因为某公司还处在 PHP 5.2 的水平上。

但,文法确实很赞,给了我一些思路。

如果协助以编译工具,或者稍微写代码的时候允许繁琐一点,就能比较完美的实现函数参数类型校验了。

<?php

function foo($a, $b) {
    Argument::i(func_get_args())
        ->test(1, 'string')
        ->test(2, 'number');
}

文法、性能上都有所考虑了。

我还没说完,等我晚上更。