【问题标题】:How to permanently typecast class properties in PHP?如何在 PHP 中永久类型转换类属性?
【发布时间】:2020-05-05 04:07:40
【问题描述】:

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

OUTSIDE CODE 可以将 Item 属性转换为任何其他 PHP 类型(布尔值、整数、浮点数、字符串、数组和对象等)——另一个巨大的错误。

考虑这个例子:

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

仅仅是受保护的和私有的属性我们不能从外部改变它们的类型吗?或者这也适用于公共财产?

【问题讨论】:

  • 永久我的意思是表达式(string)$first->foo 已被临时转换为或返回为不同类型的值。我希望表达式 $first->foo 被永久类型转换。
  • 再一次,这没有意义,因为这不是语言的工作方式。没有办法做到这一点,因为这不是操作的工作方式,也不是语言的工作方式。我想我不能再帮你了。不过我试过了。祝你好运!
  • 那些标签无关紧要,也没用。它们不应该应用于这个问题。请不要将它们添加回来。
  • @CodyGray 嘿伙计,你能解释一下ooppublic 标签与问题无关吗?我同意variables 标签,因为它说它模棱两可。
  • 这不是面向对象编程的问题,所以[oop]标签不相关。您只是在询问类型转换,这不是 OOP 功能,也与 OOP 设计无关。 [public] 标签根本不应该存在。它没有提供有关问题的任何有用的上下文信息。

标签: php oop casting properties private-members


【解决方案1】:

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

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

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

这对$string 完全没有影响:

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

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

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

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

问题的“永久”部分特别容易被误导,因为在 PHP 中变量通常没有类型

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

【讨论】:

  • 1.所以我们不能立即在 php 中对变量进行类型转换,是吗? 2. 如果类型转换的唯一方法实际上是将另一个值(具有不同类型的相同值)重新分配给变量,那么就没有任何方法可以对私有或受保护的属性进行类型转换,是吗?
  • 同样,类型转换是一种不会影响操作数的操作。类型转换不会改变变量的类型,但会产生所需类型的新值。您不能从类外部修改私有或受保护变量......除非它们有访问器(想想setFoo($foo))。
  • 能否给typecasting的定义提供一些参考。
  • 这越来越远了。链接的文档正确解释了类型转换的工作原理。您可以继续自己研究类型理论,以及类型转换在不同语言中的工作方式。希望我帮助了你。祝你好运!
【解决方案2】:

您的问题是基于对术语 typecasting 含义的误解。PHP Manual's page on type casting 和整个手册通常是不充分的,并且不是用于学习php语言。另外,它假设您了解其他编程语言,例如 C。

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

在计算机科学中,类型转换、类型转换、类型强制和类型杂耍是将表达式从一种数据类型更改为另一种数据类型的不同方法。

官方手册使用了三个术语,分别是type jugglingtype conversiontype cast。从第一段就可以猜到,类型杂耍类型转换是一回事。在第一段中,他们说:

请注意,这不会改变操作数本身的类型;唯一的变化是操作数的求值方式...

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

PHP 中的类型转换与 C:... 中的工作方式非常相似

所以,答案是,我们可以放心地假设 C 语言中的类型转换 的定义适用于 PHP 语言。在 C 语言中,类型转换 的定义与 Wikipedia 定义相同,即仅转换表达式的数据类型。以下摘录摘自本书The C Programming Language by K&R, 2nd edition,第2.7节,第45页:

在构造(type-name) expression中,表达式被转换为命名类型... ...强制转换的确切含义就像将表达式分配给特定类型的变量... ...我们可以使用sqrt((double) n)... ...请注意, cast 会产生正确类型的 n 值,n 本身不会改变。

这总结了 type cast 在 php 中的工作方式与 type juggling 相同的事实,因为所作用的变量(操作数)的数据类型没有改变。您可以使用函数settype() 来转换变量的数据类型。

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

要强制将变量转换为特定类型,可以cast变量或对其使用 settype() 函数。

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

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

很明显,settype($myObj->myPubProp, required-type) 可以轻松地将公共属性转换为不同的类型。有趣的是,与user yivi's original answer 中的建议相反,privatedprotected 属性可以被评估并且可以从类外部转换它们的类型[1][@ 987654328@]。

方法一:使用引用:

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  

【讨论】:

    【解决方案3】:

    类型转换类属性现在在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
    


    致命错误:未捕获的 TypeError:类型化属性 User::$id 必须是 int,在 [...][...]:7 中使用的字符串 堆栈跟踪: #0 {main} 在第 7 行的 [...][...] 中抛出

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

    这是sandbox link在线试用。

    【讨论】:

    • 这不是类型 casting。这些是类型化的属性。这是对另一个问题的回答。
    • 来自问题 我希望表达式 $first->foo 被永久类型转换。 。这正是我的回答所描述的。他能够将 id 转换为字符串。
    • 不,类型转换是将表达式从一种类型转换为另一种类型的操作。它发生在运行时。您正在描述声明属性的类型。不是操作,而是声明。它发生在编译时。这不是类型转换。您要么误解了问题和/或概念。
    猜你喜欢
    • 2011-05-02
    • 2011-06-30
    • 2021-04-22
    • 1970-01-01
    • 2013-12-02
    • 2021-01-22
    • 2020-12-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多