如何在 PHP 中永久转换 class 属性?

How to permanently typecast class properties in PHP?

我一直在阅读 the "Visibility" section of the PHP manual,在第一个评论中,有人提到:

OUTSIDE CODE can cast Item properties to any other PHP types (booleans, integers, floats, strings, arrays, and objects etc.) -- another huge mistake.

考虑这个例子:

class base {
    public $foo = 1;
}

$first = new base();

(string)$first->foo; //I thought just this expression would typecast
var_dump($first->foo); //but I found it still is int


$first->foo = (string)$first->foo;    
var_dump($first->foo); //ok so public props can be typecasted

难道只有受保护的私有属性我们不能从外部改变它们的类型吗?或者这也适用于 public 属性吗?

你正在做的是用一个新值覆盖 属性,它恰好是不同的类型。

类型转换不影响原始变量或值。它创建一个新的类型转换类型的值,如果你想保留你需要分配它。

你问的与对象属性可见性无关,但要理解类型转换是一种不影响其操作数的操作。

这对 $string 完全没有任何作用:

$string = "123";
(int)$string;

... 并且类型转换值丢失,因为我们没有分配操作的结果

如果满足以下几个条件,我们可以使用以下内容覆盖 $class::$someInteger 的值:

$class->someInteger = (string) 123;
  1. 属性 是 public。 (您显然不能从 class 外部直接访问 privateprotected 属性。您可以通过使用反射或奇怪的东西来绕过这个 getter returns 对 属性 的 引用 ,但两者对于生产代码来说都是非常糟糕的想法)。
  2. 您没有使用 PHP 7.4 typed properties,并为其声明了类型。

问题的 "permanently" 部分特别容易被误导,因为在 PHP 中通常变量 没有类型 .

您可以将任何类型的值赋给任何变量。当它们确实有类型(PHP 7.4 类型属性)时,没有实用的方法来更改定义的类型(同样,可能 是一种使用反射的方法......但是我不会去那里)。

你的问题是基于对术语 typecasting 的含义的误解。 PHP Manual's page on type casting 和整个手册一般来说,是不充分的,不是自己的-包含学习 php 语言的规范参考。此外,它假定您了解其他编程语言,例如 C。

类型转换未定义为变量的数据类型转换;它是 expression 的数据类型转换——一般来说,在大多数编程语言中都是如此。 Wikipedea 定义如下:

In computer science, type conversion, type casting, type coercion, and type juggling are different ways of changing an expression from one data type to another.

官方手册使用了三个术语,即type jugglingtype conversiontype casting.从第一段可以猜到,type jugglingtype conversion是一回事。他们在第一段中说:

Note that this does not change the types of the operands themselves; the only change is in how the operands are evaluated...

应该清楚 type juggling 绝对不会改变变量的类型。从 php 手册看来,type jugglingtype casting 是两个不同的概念。问题是,由于 PHP 手册从未定义这些术语,我们如何确定这两个术语是否相同以及它们的实际含义。在 Type Casting 文章中,手册说:

Type casting in PHP works much as it does in C:...

所以,答案是,我们可以安全地假设来自 C 语言的 类型转换 的定义适用于 PHP 语言。 C语言中type casting的定义和维基百科的定义一样,只是表达式的数据类型被转换。以下摘录自书 The C Programming Language by K&R, 2nd edition,第 2.7 节,第 45 页:

In the construction (type-name) expression, the expression is converted to the named type... ...The precise meaning of cast is as if the expression were assigned to a variable of the specific type... ...we can use sqrt((double) n)... ...Note that cast produces the value of n in the proper type, n itself is not altered.

这总结了 php 中的 type castingtype juggling 的工作方式相同,因为数据类型所作用的变量(操作数)的数量不变。您可以使用函数 settype() 来转换变量的数据类型。

正如第一段中指出的那样,php manual's page on types 在最后一段中给出了以下 技术上错误的 评论:

To forcibly convert a variable to a certain type, either cast the variable or use the settype() function on it.

现在,您知道 php 中的 type casting 的实际含义以及您为什么会有这种误解,最好将您的问题改写如下:

改写问题:如何永久转换PHP中class属性的数据类型。

显然 public 属性将很容易被 settype($myObj->myPubProp, required-type) 转换为不同的类型。有趣的是,与 user yivi's original answer, privated and protected properties can be assessed and can have their type converted from outside the class[1][] 中的建议相反。

方法一:使用引用:

class myClass {
    private $prop = 786; //Could be protected too.    

    public function &assess_priv(){
        return $this->prop;        
    }
    public function display_prop() {
        echo var_dump($this->prop);
    } 
}

$obj = new myClass;
$newObjProp = &$obj->assess_priv();
settype($newObjProp, "string");
$obj->display_prop(); //converted the data type of private property of a class  

方法二:使用PHP属性重载

error_reporting(E_ALL);

class myClass {
    private $prop = 786; //Could be protected too.    

    public function __set($name, $value)
    {
        $this->$name = $value;
    }

    public function __get($name)
    {
        return $this->$name;
    } 
}

$obj = new myClass;
var_dump($obj->prop);
$obj->prop = (string)$obj->prop; //Interestingly, settype($obj->prop, "string"); can't be used
echo "</br>";
var_dump($obj->prop); //converted the data type of private property of a class  

类型转换 class 属性现在可用于 php7.4

<?php
class User {
    public int $id;
    public string $name;
}
$user = new User;
$user->id = 123; // this will work
$user->id = "hello world"; // throws fatal error


Fatal error: Uncaught TypeError: Typed property User::$id must be int, string used in [...][...]:7 Stack trace: #0 {main} thrown in [...][...] on line 7

您需要切换到 php7.4。此功能现已在 7.4 link to their official docs

中可用

这是 sandbox link 在线试用。