php hhvm_没有PHP 7或HHVM,我们可以在PHP中拥有静态类型吗?

php hhvm

Now that PHP 7 has been out for a while with interesting features like error handling, null coalescing operator, scalar type declarations, etc., we often hear the people still stuck with PHP 5 saying it has a weak typing system, and that things quickly become unpredictable.

既然PHP 7已经出现了一段时间,它具有有趣的功能,例如错误处理,空合并运算符,标量类型声明等,我们经常听到人们仍然对PHP 5感到困惑,称它的打字系统很弱,而且很快变得不可预测

Vector illustration of programmer's desktop

Even though this is partially true, PHP allows you to keep control of your application when you know what you’re doing. Let’s see some code examples to illustrate this:

尽管这部分是正确的,但是PHP允许您在知道自己在做什么时就可以控制应用程序。 让我们看一些代码示例来说明这一点:

function plusone($a)
{
    return $a + 1;
}

var_dump(plusone(1));
var_dump(plusone("1"));
var_dump(plusone("1 apple"));
// output

int(2)
int(2)
int(2)

Our function will increment the number passed as an argument by one. However, the second and third calls are passing a string, and the function still returns integer values. This is called string conversion. We can make sure that the user passes a numeric value through validation.

我们的函数会将作为参数传递的数字加1。 但是,第二和第三次调用传递了一个字符串,并且该函数仍返回整数值。 这称为字符串转换 。 我们可以确保用户通过验证传递数字值。

function plusone($a)
{
    if ( !is_numeric($a) )
    {
        throw new InvalidArgumentException("I can only increment numbers!", 1);
    }

    return $a + 1;
}

This will throw an InvalidArgumentException on the third call as expected. If we specify the desired type on the function prototype…

这将按预期在第三个调用上引发InvalidArgumentException 。 如果我们在函数原型上指定所需的类型…

function plusone(int $a)
{
    return $a + 1;
}

var_dump(plusone(1));
var_dump(plusone("1"));
var_dump(plusone("1 apple"));
// output

PHP Catchable fatal error:  Argument 1 passed to plusone() must be an instance of int, integer given, called in /vagrant/test_at/test.php on line 7 and defined in /vagrant/test_at/test.php on line 2

This error seems a bit weird at first, because the first call to our function is using an integer!

首先,这个错误似乎有点怪异,因为对我们函数的第一个调用使用整数!

If we read the message carefully, we’ll see that the error message says “must be an instance of int” – it assumes that integer is a class, because PHP prior to version 7 only supported type hinting of classes!

如果我们仔细阅读消息,我们将看到错误消息显示“必须是int的实例 ” –假定integer是一个类,因为版本7之前PHP仅支持类的类型提示!

Things get even more awkward with function return arguments in PHP 5. In short, we can’t lock in their types automatically and we should check the expected value after the function call returns a value.

PHP 5中的函数返回参数使事情变得更加尴尬。简而言之,我们不能自动锁定它们的类型,我们应该在函数调用返回值之后检查期望值。

增强型 (Augmented Types)

Prior to the release of PHP 7, the team at Box came up with a nice idea to solve the typing safety problem on their PHP 5 application. After using assertions, type hints, etc., they decided to work on a cleaner solution for this problem.

在发布PHP 7之前, Box的团队提出了一个好主意,以解决其PHP 5应用程序中的键入安全性问题。 在使用断言,类型提示等之后,他们决定针对此问题开发更干净的解决方案。

We’ve seen how Facebook pushed PHP a little bit forward by launching HHVM and Hack, but the team at Box didn’t want to fork the PHP source code or modify anything in the core. Their solution was to create a separate extension called augmented types to parse the method’s phpDoc and assert types on runtime.

我们已经看到Facebook通过启动HHVMHack来如何将PHP向前推进一点,但是Box团队不希望派发PHP源代码或修改内核中的任何内容。 他们的解决方案是创建一个单独的扩展,称为增强类型,以解析该方法的phpDoc并在运行时声明类型。

安装 (Installation)

The below extension is meant to be used with PHP 5 – if you’re on PHP 7, just sit back and enjoy the ride!

以下扩展名旨在与PHP 5配合使用-如果您使用的是PHP 7,请坐下来享受旅程!

The installation process is not very complicated, and doesn’t require any specific configuration. The instructions below apply to Ubuntu, but are easily applicable to other *nix based OS as well.

安装过程不是很复杂,不需要任何特定的配置。 以下说明适用于Ubuntu,但也很容易适用于其他基于* nix的操作系统。

# update system
sudo apt-get update

# install required dependencies
sudo apt-get install php5-dev bison flex

# clone the repo
git clone git@github.com:box/augmented_types.git

# install extension

phpize
./configure --enable-augmented_types
make
make test
sudo make install

We must tell PHP to load our extension by editing the php.ini file.

我们必须告诉PHP通过编辑php.ini文件来加载扩展。

# Get php.ini location from PHP info. This will print the cli configuration file, you may need to edit /etc/php5/fpm/php.ini )
php -i | grep 'Loaded Configuration File'

# output: /etc/php5/cli/php.ini
vim /etc/php5/cli/php.ini
# Get `extension_dir` the PHP info
php -i | grep extension_dir
# output: extension_dir => /usr/lib/php5/20100525 => /usr/lib/php5/20100525

# Add this line at the end of the file
zend_extension=/usr/lib/php5/20100525/augmented_types.so

The extension can be enabled on a per-file basis using the ini_set function.

可以使用ini_set函数按文件启用扩展名。

ini_set("augmented_types.enforce_by_default",1);

Or directly on the php.ini configuration file. Be sure to check the documentation for more details about the installation process.

或直接在php.ini配置文件上。 确保检查文档以获取有关安装过程的更多详细信息。

用法 (Usage)

We mentioned earlier that the extension uses phpDoc for function/method prototypes. Most of its functionality can be explained through code examples.

前面我们提到,该扩展将phpDoc用于函数/方法原型。 可以通过代码示例来解释其大多数功能。

/**
 * Add one
 *
 * @param   int $a
 * @return    int
 */
function plusone($a)
{
    return $a + 1;
}

var_dump(plusone(1));
var_dump(plusone("1"));
var_dump(plusone("1 apple"));

You might think you’ll be able to guess the output of the above code, but you’d probably be wrong!

您可能认为您可以猜出上述代码的输出,但是您可能错了!

int(2)
PHP Fatal error:  Wrong type encountered for argument 1 of function plusone, was expecting a integer but got a (string) '1' in /vagrant/test_at/test.php on line 15

Even the second call doesn’t pass! This happens because we’re not doing the PHP conversion we talked about earlier, the function requires us to strictly pass an integer. Now, what about calling it using a float?

即使第二通电话也没有通过! 发生这种情况是因为我们没有进行前面提到PHP转换,该函数要求我们严格传递一个整数。 现在,使用浮点数调用该怎么办?

var_dump(plusone(1.5));
PHP Fatal error:  Wrong type encountered for argument 1 of function plusone, was expecting a integer but got a (float) 1.500000 in /vagrant/test_at/test.php on line 14

We made our function accept two types of arguments (int and float) by using the composite types definition.

通过使用复合类型定义,我们使函数接受两种类型的参数(int和float)。

/**
 * Add one
 *
 * @param   int|float $a
 * @return    int
 */
function plusone($a)
{
    return $a + 1;
}

var_dump(plusone(1));
var_dump(plusone(1.5));

Now our function should work as expected.

现在我们的功能应该可以正常工作了。

int(2)
PHP Fatal error:  Wrong type returned by function plusone, was expecting a integer but got a (float) 2.500000 in /vagrant/test_at/test.php on line 0

Oops! We should also define the return type for our function or cast the return value to match the phpDoc.

糟糕! 我们还应该为函数定义返回类型,或者将返回值强制转换为与phpDoc相匹配。

/**
 * Add one
 *
 * @param   int|float $a
 * @return    int|float
 */
function plusone($a)
{
    return $a + 1;
}

We can also work with compound types: the following example sums the elements of an array.

我们还可以使用复合类型:以下示例对数组的元素求和。

/**
 * Calculate sum
 *
 * @param   array $nums
 * @return    int
 */
function sum($nums)
{
    $sum = 0;
    foreach ($nums as $value) {
        $sum += $value;
    }

    return $sum;
}

var_dump(sum([10, 12, 76]));

// output
int(98)

The function returns the expected value. What if the array contains something other than integers, though?

该函数返回期望值。 但是,如果数组包含整数以外的内容怎么办?

var_dump(sum([10, 12, "something"]));

// output
int(22)

The extension gives us the ability to work with array types. The previous example will throw a fatal error as expected.

该扩展使我们能够处理数组类型 。 前面的示例将按预期引发致命错误。

/**
 * Calculate sum
 *
 * @param   int[] $nums
 * @return    int
 */
function sum($nums)
{
    $sum = 0;
    foreach ($nums as $value) {
        $sum += $value;
    }

    return $sum;
}

var_dump(sum([10, 12, 76]));
var_dump(sum([10, 12, "something"]));
int(98)
PHP Fatal error:  Wrong type encountered for argument 1 of function sum, was expecting a (integer)[] but got a array in /vagrant/test_at/test.php on line 20

An interesting case is when we have a function that accepts an arbitrary number of arguments. We can make our previous function return the sum of all the passed arguments.

一个有趣的情况是,当我们有一个函数可以接受任意数量的参数时。 我们可以使上一个函数返回所有传递的参数的和。

/**
 * Calculate sum
 *
 * @param   *int $nums
 * @return    int
 */
function sum($nums)
{
    $args = func_get_args();
    $sum = 0;
    foreach ($args as $value) {
        $sum += $value;
    }

    return $sum;
}

var_dump(sum(10, 12, 76));

The *int type definition lets our function receive any number of arguments as long as it’s an integer. We can combine the *int and int[] type definitions to make our function accept both previous cases.

*int类型定义使我们的函数可以接收任意数量的参数,只要它是整数即可。 我们可以结合使用*intint[]类型定义,以使我们的函数接受前面两种情况。

/**
 * Calculate sum
 *
 * @param   *int|int[] $nums
 * @return    int
 */
function sum($nums)
{
    if ( !is_array($nums) )
    {
        $nums = func_get_args();
    }

    $sum = 0;
    foreach ($nums as $value) {
        $sum += $value;
    }

    return $sum;
}

var_dump(sum(10, 12, 76));
var_dump(sum([10, 12, 76]));

Now both function calls will return the same value (int(98)).

现在,两个函数调用将返回相同的值( int(98) )。

默认参数 (Default Arguments)

Most of the time, functions contain optional arguments which may be initialized using default values. We use the void type definition to tell the extension that our value is optional but OK if passed in.

大多数时候,函数包含可选参数,可以使用默认值对其进行初始化。 我们使用void类型定义告诉扩展名,我们的值是可选的,但如果传入则可以。

/**
 * SSH to server.
 *
 * @param   string      $url
 * @param   int|void    $port
 * @return  bool
 */
function ssh($url, $port = 2222)
{
    return true;
}

Note: When an argument has a default value it will not enforce the specified type. It means that passing a string on the port argument won’t throw an error.

注意 :当参数具有默认值时,它将不强制执行指定的类型。 这意味着在port参数上传递字符串不会引发错误。

返回类型 (Return Types)

The same thing we said earlier about argument types applies to return type definitions. We can specify normal scalar types, classes, composite types and array types. Every function should have a @return <type> definition and must use @return void if it doesn’t return anything.

我们前面谈到的参数类型同样适用于返回类型定义。 我们可以指定普通标量类型,类,复合类型和数组类型。 每个函数应具有@return <type>定义,并且如果不返回任何内容,则必须使用@return void

class User
{
    protected $id;

    protected $name;

    /**
     * Constructor
     * @param int       $id
     * @param string    $name
     * @return void
     */
    public function __construct($id, $name)
    {
        $this->id = $id;
        $this->name = $name;
    }

    /**
     * Return the user info as a string.
     *
     * @return    string
     */
    public function __toString()
    {
        return $this->name;
    }
}

忽略文件 (Ignoring Files)

Most of the time, our application contains other people’s packages, and we don’t want the augmented types extension to throw errors and halt our application because of missing definitions. Luckily, the extension provides a clean way to blacklist and whitelist files and folders.

大多数情况下,我们的应用程序包含其他人的软件包,并且我们不希望扩展类型扩展会因缺少定义而抛出错误并暂停我们的应用程序。 幸运的是,该扩展名提供了一种将文件和文件夹列入黑名单白名单的干净方法。

augmented_types_blacklist([__DIR__."/vendor"]);

The extension will now ignore our vendor directory. If we have some of our own inspectable directories inside the vendor directory, we can use the whitelist function to add them back. You can read more about this in the documentation.

该扩展名现在将忽略我们的供应商目录。 如果供应商目录中有一些我们自己的可检查目录,则可以使用白名单功能将其重新添加。 您可以在文档中阅读有关此内容的更多信息。

augmented_types_whitelist([__DIR__."/vendor/mylib"]);

We can also achieve the same result using the php.ini file, and this is the recommended way to do it, according to the extension’s developers.

根据扩展程序的开发人员,我们还可以使用php.ini文件获得相同的结果,这是推荐的方法。

# php.ini
augmented_types.whitelist=./vendor
augmented_types.blacklist=./vendor/mylib

PHP 7更改 (PHP 7 Changes)

PHP 7 introduced scalar type declarations and return types to functions/methods, thus eliminating the need for further validation on arguments and return types. Check out the list of changes on the official PHP website.

PHP 7引入了标量类型声明和函数/方法的返回类型,从而消除了对参数和返回类型进行进一步验证的需要。 在PHP官方网站上查看更改列表

If PHP 7 already supports this, what could be the benefit of installing a new extension?

如果PHP 7已经支持此功能,那么安装新扩展的好处是什么?

Well, the extension provides a wide variety of options that we don’t have in PHP 7, like:

好吧,扩展提供了PHP 7中没有的各种选项,例如:

  • Composite types (@param string|int $var)

    复合类型( @param string|int $var )

  • Array types (@param int[] $var)

    数组类型( @param int[] $var )

  • Forcing functions to return a value (at least void)

    强制函数返回值(至少void )

结论 (Conclusion)

It’s always a good idea to upgrade to PHP 7 and benefit from all the exciting new features. However, we don’t always have the luxury of using cutting edge technology in our projects.

升级到PHP 7并从所有令人兴奋的新功能中受益始终是一个好主意。 但是,我们并不总是拥有在项目中使用尖端技术的奢侈。

The augmented types extension will absolutely slow down the application’s runtime (as would be expected), which is why it should only be used during development and testing, to keep the production server clean and fast.

增强类型扩展绝对会减慢应用程序的运行时间(这是可以预期的),这就是为什么仅在开发和测试期间使用它以保持生产服务器的清洁和快速的原因。

What do you think about the extension? Is it useful? Do you have other ideas on how to do what it does? We’re curious to know what you think, let us know!

您如何看待扩展名? 它有用吗? 您对如何执行操作还有其他想法吗? 我们很想知道您的想法,请告诉我们!

翻译自: https://www.sitepoint.com/can-we-have-static-types-in-php-without-php-7-or-hhvm/

php hhvm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值