我们可以限制PHP变量以仅接受某些类型的值

Siz*_*ode 3 php

我想知道是否有可能限制php变量只接受它定义为接受的某种类型的变量.

例如,如果我们在C#中看到

public int variable = 20;
public string variable2 = "Hello World";
Run Code Online (Sandbox Code Playgroud)

那么如果我想限制变量的类型,那将是什么样的PHP.

public int $variable = 20;
Run Code Online (Sandbox Code Playgroud)

所以,如果我尝试将字符串分配给整数变量,我得到错误.

public int $varaible = "Hello World"; //As type is integer, it should throw error.
Run Code Online (Sandbox Code Playgroud)

是否有这样的事情在PHP中为变量定义类型之前给它赋值?

eli*_*ide 10

TL; DR不直接,没有.PHP不是严格类型的.但是,在函数参数或类的属性的上下文中,有一些可能对您有用的变通方法.

答案长: PHP不是严格类型的语言,而是松散类型的.无论初始化方式如何,您都可以为变量提供所需的任何值.所以,你不能简单地键入类似的东西,int $myVar并期望$myVar = "foo";抛出错误.但PHP确实提供了一些方便的功能,可以在处理函数参数或类的属性时使您达到同样的目的.

选项1:输入提示

您可以对函数参数使用"类型提示":

class SomeClass 
{
    /* code here */
}

function foo(SomeClass $data)
{
    /* code here */
}
Run Code Online (Sandbox Code Playgroud)

foo()只接受类型的参数SomeClass.传递它,比如说,int会抛出一个致命的错误.这并不在PHP <7工作,如果参数旨在为基本类型,比如int,string等等,所以你不能这样做function foo(int $data) {...}.也就是说,有一些库试图以牺牲一点速度为代价来强制它运行.此外,PHP 7为这种事情增加了很多支持,基于PHP的Hack语言也是如此.

优点:

  • 简单
  • 直观的

缺点:

  • 仅适用于程序定义的类
  • 基本类型不可用

选项2:吸气剂和二传手

您也可以使用getter和setter,如下所示:

class SomeClass 
{
    private $foo = 0;

    function setFoo($val = 0)
    {
        // force it to be an int
        if (is_integer($val) {
            $this->foo = $val;
        } else {
            // throw an error, raise an exception, or otherwise respond
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

优点:

  • 比较容易
  • 比较直观

缺点:

  • 仅适用于程序定义的类
  • 基本类型不可用
  • 需要大量代码

选项3:魔术方法

这种方法是我最喜欢的,也是最复杂的.使用__set()magic方法处理类属性.

class MyClass {
    private $type = 0; // we will force this to be an int
    private $string = ''; // we will force this to be a string
    private $arr = array(); // we will force this to be an array
    private $percent = 0; // we will force this to be a float in the range 0..100

    function __set($name, $value) {
        switch ($name) {
            case "type":
                $valid = is_integer($value);
                break;
            case "string":
                $valid = is_string($value);
                break;
            case "arr":
                $valid = is_array($value);
                break;
            case "percent":
                $valid = is_float($value) && $value >= 0 && $value <= 100;
                break;
            default:
                $valid = true; // allow all other attempts to set values (or make this false to deny them)
        }

        if ($valid) {
            $this->{$name} = $value;

            // just for demonstration
            echo "pass: Set \$this->$name = ";
            var_dump($value);
        } else {
            // throw an error, raise an exception, or otherwise respond

            // just for demonstration
            echo "FAIL: Cannot set \$this->$name = ";
            var_dump($value);
        }
    }
}

$myObject = new MyClass();
$myObject->type = 1; // okay
$myObject->type = "123"; // fail
$myObject->string = 1; // fail
$myObject->string = "123"; // okay
$myObject->arr = 1; // fail
$myObject->arr = "123"; // fail
$myObject->arr = array("123"); // okay
$myObject->percent = 25.6; // okay
$myObject->percent = "123"; // fail
$myObject->percent = array("123"); // fail
$myObject->percent = 123456; // fail
Run Code Online (Sandbox Code Playgroud)

优点:

  • 比较容易
  • 直观的
  • 非常强大:一个统治者可以统治所有人

缺点:

  • 仅适用于程序定义的类
  • 基本类型不可用
  • 需要大量的switching或if/ else逻辑
  • IDE可能导致问题无法正确自动完成属性类型

是这种方法演示.

闭幕思考

最后,如果您使用的是像PHPStorm这样的IDE,请不要忘记PHPDoc类型提示:

/* @var integer */
$foo = 0; // will result in warnings if the IDE is configured properly and you try to do something like substr($foo, 1, 4);
Run Code Online (Sandbox Code Playgroud)

如果你真的想要硬核,那么你可以使用Hack进行强类型操作,代价是使你的代码不那么便携,而且与主要的IDE相比(现在)兼容性差.

当然,这些都不能替代显式验证用户输入并彻底测试应用程序对意外输入类型的响应.