php 用户定义对象的类型转换

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1147109/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 01:13:41  来源:igfitidea点击:

Type casting for user defined objects

phpcasting

提问by Arsham

Just like we do with __ToString, is there a way to define a method for casting?

就像我们对 __ToString 所做的那样,有没有一种方法可以定义一种转换方法?

$obj = (MyClass) $another_class_obj;

回答by troelskn

There is no need to type cast in php.

不需要在 php 中输入类型转换。



Edit:Since this topic seems to cause some confusion, I thought I'd elaborate a little.

编辑:由于这个话题似乎引起了一些混乱,我想我会详细说明一下。

In languages such as Java, there are two things that may carry type. The compiler has a notion about type, and the run time has another idea about types. The compilers types are tied to variables, whereas the run time engine tracks the type of values (Which are assigned to variables). The variable types are known at compile time, whereas the value types are only known at run time.

在 Java 等语言中,有两种可能带有类型的东西。编译器有一个关于类型的概念,而运行时有另一个关于类型的概念。编译器类型与变量相关联,而运行时引擎跟踪值的类型(分配给变量)。变量类型在编译时已知,而值类型仅在运行时已知。

If a piece of input code violates the compilers type system, the compiler will barf and halt compilation. In other words, it's impossible to compile a piece of code that violates the static type system. This catches a certain class of errors. For example, take the following piece of (simplified) Java code:

如果一段输入代码违反了编译器的类型系统,编译器将停止编译。换句话说,编译一段违反静态类型系统的代码是不可能的。这会捕获特定类别的错误。例如,采用以下(简化的)Java 代码:

class Alpha {}

class Beta extends Alpha {
  public void sayHello() {
    System.out.println("Hello");
  }
}

If we now did this:

如果我们现在这样做:

Alpha a = new Beta();

we would be fine, since Betais a subclass of Alpha, and therefore a valid value for the variable aof type Alpha. However, if we proceed to do:

我们会很好,因为Beta是 的子类Alpha,因此是a类型变量的有效值Alpha。但是,如果我们继续这样做:

a.sayHello();

The compiler would give an error, since the method sayHelloisn't a valid method for Alpha- Regardless that we know that ais actually a Beta.

编译器会报错,因为该方法sayHello不是有效的方法Alpha- 不管我们知道它a实际上是一个Beta.

Enter type casting:

输入类型转换:

((Beta) a).sayHello();

Here we tell the compiler that the variable ashould - in this case - be treated as a Beta. This is known as type casting. This loophole is very useful, because it allows polymorphism in the language, but obviously it is also a back door for all sorts of violations of the type system. In order to maintain some type safety, there are therefore some restrictions; You can only cast to types that are related. Eg. up or down a hierarchy. In other words, you wouldn't be able to cast to a completely unrelated class Charlie.

在这里,我们告诉编译器变量a应该 - 在这种情况下 - 被视为Beta. 这称为类型转换。这个漏洞非常有用,因为它允许语言中的多态性,但显然它也是各种违反类型系统的后门。为了保持某种类型的安全性,因此存在一些限制;您只能转换为相关的类型。例如。向上或向下层次结构。换句话说,您将无法转换为完全不相关的 class Charlie

It's important to note that all this happens in the compiler - That is, it happens before the code even runs. Java can still get in to run time type errors. For example, if you did this:

需要注意的是,所有这些都发生在编译器中——也就是说,它甚至在代码运行之前就发生了。Java 仍然会出现运行时类型错误。例如,如果你这样做:

class Alpha {}

class Beta extends Alpha {
  public void sayHello() {
    System.out.println("Hello");
  }
}

class Charlie extends Alpha {}

Alpha a = new Charlie();
((Beta) a).sayHello();

The above code is valid for the compiler, but at run time, you'll get an exception, since the cast from Betato Charlieis incompatible.

上面的代码对编译器有效,但在运行时,你会得到一个异常,因为从Betato 的转换Charlie是不兼容的。

Meanwhile, back at the PHP-farm.

同时,回到 PHP 农场。

The following is valid to the PHP-compiler - It'll happily turn this into executable byte code, but you'll get a run time error:

以下内容对 PHP 编译器有效 - 它很乐意将其转换为可执行字节代码,但您会收到运行时错误:

class Alpha {}

class Beta extends Alpha {
  function sayHello() {
    print "Hello";
  }
}
$a = new Alpha();
$a->sayHello();

This is because PHP variables don't have type. The compiler has no idea about what run time types are valid for a variable, so it doesn't try to enforce it. You don't specify the type explicitly as in Java either. There are type hints, yes, but these are simply run time contracts. The following is still valid:

这是因为 PHP 变量没有类型。编译器不知道哪些运行时类型对变量有效,因此它不会尝试强制执行它。您也不像在 Java 中那样显式指定类型。有类型提示,是的,但这些只是运行时合同。以下仍然有效:

// reuse the classes from above
function tellToSayHello(Alpha $a) {
  $a->sayHello();
}
tellToSayHello(new Beta());

Even though PHP variablesdon't have types, the valuesstill do. A particular interesting aspect of PHP, is that it is possible to change the type of a value. For example:

尽管 PHP变量没有类型,但仍然有。PHP 的一个特别有趣的方面是可以更改值的类型。例如:

// The variable $foo holds a value with the type of string
$foo = "42";
echo gettype($foo); // Yields "string"
// Here we change the type from string -> integer
settype($foo, "integer");
echo gettype($foo); // Yields "integer"

This feature some times confused with type casting, but that is a misnomer. The type is still a property of the value, and the type-change happens in runtime - not at compile time.

此功能有时会与类型转换混淆,但这是用词不当。类型仍然是值的一个属性,并且类型更改发生在运行时 - 而不是在编译时。

The ability to change type is also quite limited in PHP. It is only possible to change type between simple types - not objects. Thus, it isn't possible to change the type from one class to another. You can create a new object and copy the state, but changing the type isn't possible. PHP is a bit of an outsider in this respect; Other similar languages treat classes as a much more dynamic concept than PHP does.

PHP 中更改类型的能力也非常有限。只能在简单类型之间更改类型 - 而不是对象。因此,不可能将类型从一个类更改为另一个类。您可以创建一个新对象并复制状态,但无法更改类型。PHP 在这方面有点局外人;其他类似的语言将类视为一个比 PHP 更动态的概念。

Another similar feature of PHP is that you can clone a value as a new type, like this:

PHP 的另一个类似功能是您可以将值克隆为新类型,如下所示:

// The variable $foo holds a value with the type of string
$foo = "42";
echo gettype($foo); // Yields "string"
// Here we change the type from string -> integer
$bar = (integer) $foo;
echo gettype($bar); // Yields "integer"

Syntactically this looks a lot like how a typecast is written in statically typed languages. It's therefore also often confused with type casting, even though it is still a runtime type-conversion.

从语法上讲,这看起来很像用静态类型语言编写的类型转换。因此它也经常与类型转换混淆,即使它仍然是运行时类型转换。

To summarise:Type casting is an operation that changes the type of a variable (notthe value). Since variables are without type in PHP, it is not only impossible to do, but a nonsensical thing to ask in the first place.

总结:类型转换是一种改变变量类型(而不是值)的操作。由于变量在 PHP 中是没有类型的,所以这不仅是不可能做到的,而且首先问是一件无意义的事情。

回答by Jrgns

Although there's no need to type cast in PHP, you might come across a situation where you would like to convert a parent object into a child object.

尽管在 PHP 中不需要类型转换,但您可能会遇到希望将父对象转换为子对象的情况。

Simple

简单的

//Example of a sub class
class YourObject extends MyObject {
    public function __construct(MyObject $object) {
        foreach($object as $property => $value) {
            $this->$property = $value;
        }
    }
}


$my_object = new MyObject();
$your_object = new YourObject($my_object);

So all you do is pass the parent object down to the child object's constructor, and let the constructor copy over the properties. You can even filter / change them as needed.

所以你要做的就是将父对象向下传递给子对象的构造函数,然后让构造函数复制属性。您甚至可以根据需要过滤/更改它们。

Advanced

先进的

//Class to return standard objects
class Factory {
    public static function getObject() {
        $object = new MyObject();
        return $object;
    }
}

//Class to return different object depending on the type property
class SubFactory extends Factory {
    public static function getObject() {
        $object = parent::getObject();
        switch($object->type) {
        case 'yours':
            $object = new YourObject($object);
            break;
        case 'ours':
            $object = new OurObject($object);
            break;
        }
        return $object;
    }
}

//Example of a sub class
class YourObject extends MyObject {
    public function __construct(MyObject $object) {
        foreach($object as $property => $value) {
            $this->$property = $value;
        }
    }
}

It's not type casting, but it does what you need.

这不是类型转换,但它可以满足您的需求。

回答by Josh

Here's a function to change the class of an object:

这是一个更改对象类的函数:

/**
 * Change the class of an object
 *
 * @param object $obj
 * @param string $class_type
 * @author toma at smartsemantics dot com
 * @see http://www.php.net/manual/en/language.types.type-juggling.php#50791
 */
function changeClass(&$obj,$new_class)
{
    if(class_exists($class_type,true))
    {
        $obj = unserialize(preg_replace("/^O:[0-9]+:\"[^\"]+\":/i",
            "O:".strlen($class_type).":\"".$new_class."\":", serialize($obj)));
    }
}

In case it's not clear, this is not my function, it was taken from a post by "toma at smartsemantics dot com" on http://www.php.net/manual/en/language.types.type-juggling.php#50791

如果不清楚,这不是我的功能,它取自http://www.php.net/manual/en/language.types.type-juggling.php上“toma at smartsemantics dot com”的帖子#50791

回答by B T

I reworked the function Josh posted (which will error because of the undefined $new_class variable). Here's what I got:

我重新编写了 Josh 发布的函数(由于未定义的 $new_class 变量会出错)。这是我得到的:

function changeClass(&$obj, $newClass)
{   $obj = unserialize(preg_replace // change object into type $new_class
    (   "/^O:[0-9]+:\"[^\"]+\":/i", 
        "O:".strlen($newClass).":\"".$newClass."\":", 
        serialize($obj)
    ));
}

function classCast_callMethod(&$obj, $newClass, $methodName, $methodArgs=array())
{   $oldClass = get_class($obj);
    changeClass($obj, $newClass);

    // get result of method call
    $result = call_user_func_array(array($obj, $methodName), $methodArgs);
    changeClass(&$obj, $oldClass);  // change back
    return $result;
}

It works just like you'd expect a class cast to work. You could build something similar for accessing class members - but I don't think I would ever need that, so i'll leave it to someone else.

它的工作原理就像您期望的类演员表工作一样。您可以构建类似的东西来访问班级成员 - 但我认为我永远不需要那个,所以我会把它留给其他人。

Boo to all the jerks that say "php doesn't cast" or "you don't need to cast in php". Bullhockey. Casting is an important part of object oriented life, and I wish I could find a better way to do it than ugly serialization hacks.

向所有说“php 不会转换”或“您不需要在 php 中转换”的混蛋们嘘声。牛曲棍球。铸造是面向对象生活的重要组成部分,我希望能找到比丑陋的序列化黑客更好的方法来做到这一点。

So thank you Josh!

所以谢谢乔希!

回答by DontBreakIt

If casting for type hinting is all you're after, this works.

如果您只需要为类型提示进行强制转换,则此方法有效。

if( is_object($dum_class_u_want) && $dum_class_u_want instanceof ClassYouWant )
{
    // type hints working now
    $dum_class_u_want->is_smart_now();
}

Yep.

是的。

回答by gnarf

I do not believe there is a overloading operator in PHP to handle that, however:

我不相信 PHP 中有一个重载运算符来处理这个问题,但是:

<?php

class MyClass {

  protected $_number;

  static public function castFrom($obj) {
    $new = new self();
    if (is_int($obj)) {
      $new->_number = $obj;
    } else if ($obj instanceOf MyNumberClass){
      /// some other type of casting
    }
    return $new;
  }
}

$test = MyClass::castFrom(123123);
var_dump($test);

Is one way to handle it.

是一种处理方式。

回答by Syed Zeeshan Shah

I think you need to type cast in order to make a better IDE. But php the language itself doesn't need type casting it does however support runtime type changes to the values in the variables. Take a look at autoboxing and unboxing. That's what php inherently does. So sorry no better than already are IDEs.

我认为您需要进行类型转换才能制作更好的 IDE。但是 php 语言本身不需要类型转换,但它支持对变量中的值进行运行时类型更改。看看自动装箱和拆箱。这就是 php 固有的功能。所以很抱歉没有比已经是 IDE 更好的了。

回答by Lucas Bustamante

I think you mean Type-Hinting.

我想你的意思是Type-Hinting

As of PHP 7.2, you can type-hint arguments in functions:

从 PHP 7.2 开始,您可以在函数中键入提示参数:

function something(Some_Object $argument) {...} # Type-hinting object on function arguments works on PHP 7.2+

But you can't type-hint it like this:

但是你不能像这样输入提示:

(Some_Object) $variable = get_some_object($id); # This does not work, even in PHP 7.2

The alternative for type-hinting objects while it isn't implemented officialy in PHP, is:

在 PHP 中没有正式实现的类型提示对象的替代方法是:

$variable = get_some_object($id); # We expect Some_Object to return
is_a($argument, 'Some_Object') || die('get_some_object() function didn't return Some_Object');

回答by Yevgeniy Afanasyev

Even on PHP 7.2 if you try simple type casting, like so

即使在 PHP 7.2 上,如果你尝试简单的类型转换,就像这样

class One
{
    protected $one = 'one';
}

class Two extends One
{
    public function funcOne()
    {
        echo $this->one;
    }
}


    $foo = new One();
    $foo = (Two) $foo;
    $foo->funcOne();

You'll get error like this

你会得到这样的错误

PHP Parse error: syntax error, unexpected '$foo' (T_VARIABLE) in xxx.php on line xxx

PHP 解析错误:xxx.php 行 xxx 中的语法错误,意外的 '$foo' (T_VARIABLE)

So you basically cannot do that, but think again, maybe you wanted only a new function on top of other public functionality of the class?

所以你基本上不能这样做,但再想一想,也许你只想要一个在类的其他公共功能之上的新功能?

You can do that using Wrapper

你可以使用 Wrapper 做到这一点

class One
{
    protected $one;
    public function __construct(string $one)
    {
        $this->one = $one;
    }
    public function pub(string $par){
        echo (__CLASS__ . ' - ' . __FUNCTION__ . ' - ' . $this->one . '-' .$par);
    }
}

class Wrapper
{
    private $obj;

    public function __construct(One $obj)
    {
        $this->obj = $obj;
    }
    public function newFunction()
    {
        echo (__CLASS__ . ' - ' . __FUNCTION__);
    }
    public function __call($name, $arguments)
    {
        return call_user_func_array([$this->obj, $name], $arguments);
    }
}

    $foo = new One('one');
    $foo->pub('par1');
    $foo = new Wrapper($foo);
    $foo->pub('par2');
    $foo->newFunction();

One - pub - one-par1

One - pub - one-par2

Wrapper - newFunction

一 - 酒吧 - 标准杆 1

一 - 酒吧 - 标准杆 2

包装器 - newFunction

What if you want to get a protected property out?

如果您想获得受保护的财产怎么办?

You can do that too

你也能做到

class One
{
    protected $one;

    public function __construct(string $one)
    {
        $this->one = $one;
    }
}


    $foo = new One('one');
    $tmp = (new class ($foo) extends One {
            protected $obj;
            public function __construct(One $obj)
            {
                $this->obj = $obj;
                parent::__construct('two');
            }
            public function getProtectedOut()
            {
                return $this->obj->one;
            }
        } )->getProtectedOut();

    echo ($tmp);

You'll get

你会得到

one

And you can get_protected_in the same way

你可以用同样的方式 get_protected_

回答by Jimmy Thomsen

I mainly need type casting to enable intellisense - so I just create a type cast helper:

我主要需要类型转换来启用智能感知 - 所以我只创建了一个类型转换助手:

function castToTest($val): Test
{
    return $val;
}
$test = castToTest(require("someFile.php"));

Returning from a file is kind of ugly and does not allow for type hinting, so this is a perfect example of how you can achieve intellisense by using a type cast helper.

从文件返回有点难看,并且不允许类型提示,所以这是一个完美的例子,说明如何使用类型转换助手来实现智能感知。