【问题标题】:Can We Restrict PHP Variables to accept only certain type of values我们可以限制 PHP 变量只接受特定类型的值吗
【发布时间】:2015-02-27 13:41:31
【问题描述】:

我想知道是否可以限制 php 变量只接受它定义为接受的某些类型的变量。

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

public int variable = 20;
public string variable2 = "Hello World";

如果我想限制变量的类型,在 php 中会是什么样子。

public int $variable = 20;

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

public int $varaible = "Hello World"; //As type is integer, it should throw error.

在为变量赋值之前,有没有在 PHP 中为变量定义类型??

【问题讨论】:

标签: php


【解决方案1】:

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

长答案: PHP 不是严格类型的语言,而是松散类型的语言。你可以给一个变量任何你想要的值,不管它是如何初始化的。因此,您不能简单地键入 int $myVar 之类的内容并期望 $myVar = "foo"; 抛出错误。但是 PHP 确实提供了一些方便的功能,让您在处理类的函数参数或属性时达到同样的目的。

选项 1:输入提示

您可以将"type hint" 用于函数参数:

class SomeClass 
{
    /* code here */
}

function foo(SomeClass $data)
{
    /* code here */
}

foo() 将只接受 SomeClass 类型的参数。传递它,比如说,int 将引发致命错误。如果参数是基本类型,如intstring 等,这在 PHP function foo(int $data) {...}。也就是说,有一些库试图以牺牲一点速度为代价来强制它工作。另外,PHP 7 对这类东西增加了很多支持,基于 PHP 的 Hack 语言也是如此。

优点:

  • 简单
  • 直观

缺点:

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

选项 2:Getter 和 Setter

您也可以使用 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
        }
    }
}

优点:

  • 相对容易
  • 比较直观

缺点:

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

选项 3:魔术方法

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

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

优点:

  • 相对容易
  • 直观
  • 极其强大:一个二传手统统统领他们

缺点:

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

这是demo of this approach

结束思想

最后,如果您使用的是 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);

如果您真的想要成为硬核,您可以使用Hack 进行强类型化,但代价是降低您的代码的可移植性和(目前)与主要 IDE 的兼容性。

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

【讨论】:

  • PHPStorm 是 PHP 的 IDE。谢谢你提到这一点。 +1。
  • @AyeshK :) 没有争论;这是我发现唯一有用的。
【解决方案2】:

没有。 PHP 不是严格类型的语言。但是,您可以在函数和方法中使用type hints

如果将类或接口指定为类型提示,则也允许其所有子级或实现。

类型提示不能用于标量类型,例如 int 或 string。资源和特征也是不允许的。

标量类型是:

  • string
  • bool
  • int
  • float

例子:

function (array $theArr) {
  // body
}

class X {
  public function __construct(SomeOtherClass $arg) {
    // body
  }

  public function setFoo(Foo $foo) {

  }
}

查看手册了解更多详情:http://php.net/manual/en/language.oop5.typehinting.php

【讨论】:

  • 对于 int 和 string ?
  • 不,不适用于intstring boolfloat
  • 我知道,但也许它应该包含在你的答案中;)
  • 值得指出实验性自动装箱式SPL Types Extension?
  • 仅数组(不区分大小写)和类名。
【解决方案3】:

你必须亲手制作,例如:

function setInt(&$var, $value) {
    if(!is_integer($value) {
        throw new Exception("Integer wanted " . gettype($value) . " received");
    }
    $var = $value;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-12
    • 2016-12-14
    相关资源
    最近更新 更多