如何在 PHP 中转换对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2226103/
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 05:37:14  来源:igfitidea点击:

How to Cast Objects in PHP

phpobjectcasting

提问by user267599

Ive some classes that share some attributes, and i would like to do something like:

我有一些共享一些属性的类,我想做一些类似的事情:

$dog = (Dog) $cat;

is it possible or is there any generic work around?

有可能还是有任何通用的解决方法?

Its not a superclass, or a interface or related in any way. They are just 2 different classes i would like php map the attributes from a cat class to a dog and give me the new object. –

它不是超类,也不是接口或以任何方式相关。它们只是 2 个不同的类,我希望 php 将属性从猫类映射到狗并给我新对象。——

i guess i have to specify a little bit more cause seem like a senseless thing to do.

我想我必须多说明一点,因为这似乎是一件毫无意义的事情。

i've classes that inherits from different parent classes cause i've made an inheritance tree based on the saving method, maybe my bad from the beginning, but the problem is that i have a lot of classes that are practically equal but interacts one with mysql and the other one with xml files. so i have:

我有从不同父类继承的类,因为我已经根据保存方法制作了一个继承树,也许我从一开始就不好,但问题是我有很多类实际上是平等的,但与之交互mysql 和另一个带有 xml 文件。所以我有:

class MySql_SomeEntity extends SomeMysqlInteract{}

and

Xml_SomeEntity extends SomeXmlInteract{}

its a little bit deeper tree but the problem its that. i cant make them inherits from the same class cause multiple inheritance is not allowed, and i cant separate current interaction with superclases cause would be a big trouble.

它的树更深一点,但问题在于。我不能让它们从同一个类继承,因为不允许多重继承,而且我不能将当前与超类的交互分开,因为这将是一个大麻烦。

Basically the attributes in each one are practical the same.

基本上每个属性中的属性都是相同的。

since i have a lot of this matching classes i would like to do some generic casting or something like it that can converts (pass the values to each attribute) and but im trying to search the simplest way to everyone of this classes.

因为我有很多这种匹配的类,所以我想做一些通用的转换或类似的东西,可以转换(将值传递给每个属性),但我试图搜索每个类的最简单的方法。

回答by Adam Puza

You can use above function for casting not similar class objects (PHP >= 5.3)

您可以使用上面的函数来转换不相似的类对象(PHP >= 5.3)

/**
 * Class casting
 *
 * @param string|object $destination
 * @param object $sourceObject
 * @return object
 */
function cast($destination, $sourceObject)
{
    if (is_string($destination)) {
        $destination = new $destination();
    }
    $sourceReflection = new ReflectionObject($sourceObject);
    $destinationReflection = new ReflectionObject($destination);
    $sourceProperties = $sourceReflection->getProperties();
    foreach ($sourceProperties as $sourceProperty) {
        $sourceProperty->setAccessible(true);
        $name = $sourceProperty->getName();
        $value = $sourceProperty->getValue($sourceObject);
        if ($destinationReflection->hasProperty($name)) {
            $propDest = $destinationReflection->getProperty($name);
            $propDest->setAccessible(true);
            $propDest->setValue($destination,$value);
        } else {
            $destination->$name = $value;
        }
    }
    return $destination;
}

EXAMPLE:

例子:

class A 
{
  private $_x;   
}

class B 
{
  public $_x;   
}

$a = new A();
$b = new B();

$x = cast('A',$b);
$x = cast('B',$a);

回答by user250120

There is no built-in method for type casting of user defined objects in PHP. That said, here are several possible solutions:

PHP 中没有用于用户定义对象类型转换的内置方法。也就是说,这里有几种可能的解决方案:

1) Use a function like the one below to deserialize the object, alter the string so that the properties you need are included in the new object once it's deserialized.

1) 使用如下所示的函数反序列化对象,更改字符串,以便在反序列化后将您需要的属性包含在新对象中。

function cast($obj, $to_class) {
  if(class_exists($to_class)) {
    $obj_in = serialize($obj);
    $obj_out = 'O:' . strlen($to_class) . ':"' . $to_class . '":' . substr($obj_in, $obj_in[2] + 7);
    return unserialize($obj_out);
  }
  else
    return false;
}

2) Alternatively, you could copy the object's properties using reflection / manually iterating through them all or using get_object_vars().

2) 或者,您可以使用反射/手动遍历所有对象或使用 get_object_vars() 来复制对象的属性。

This articleshould enlighten you on the "dark corners of PHP" and implementing typecasting on the user level.

这篇文章应该让您了解“PHP 的黑暗角落”并在用户级别实现类型转换。

回答by Trav L

Without using inheritance (as mentioned by author), it seems like you are looking for a solution that can transformone class to another with preassumption of the developer knows and understand the similarity of 2 classes.

不使用继承(如作者所述),似乎您正在寻找一种解决方案,该解决方案可以在开发人员知道并理解 2 个类的相似性的前提下,将transform一个类转换为另一个

There's no existing solution for transforming between objects. What you can try out are:

没有用于在对象之间转换的现有解决方案。您可以尝试的是:

回答by Matthew Sturges

It sounds like what you really want to do is implement an interface.

听起来您真正想做的是实现一个接口

Your interface will specify the methods that the object can handle and when you pass an object that implements the interface to a method that wants an object that supports the interface, you just type the argument with the name of the interface.

您的接口将指定对象可以处理的方法,当您将实现接口的对象传递给需要支持该接口的对象的方法时,您只需键入带有接口名称的参数即可。

回答by useless

a better aproach:

更好的方法:

class Animal
{
    private $_name = null;

    public function __construct($name = null)
    {
        $this->_name = $name;
    }

    /**
     * casts object
     * @param Animal $to
     * @return Animal
     */
    public function cast($to)
    {
        if ($to instanceof Animal) {
            $to->_name = $this->_name;
        } else {
            throw(new Exception('cant cast ' . get_class($this) . ' to ' . get_class($to)));
        return $to;
    }

    public function getName()
    {
        return $this->_name;
    }
}

class Cat extends Animal
{
    private $_preferedKindOfFish = null;

    public function __construct($name = null, $preferedKindOfFish = null)
    {
        parent::__construct($name);
        $this->_preferedKindOfFish = $preferedKindOfFish;
    }

    /**
     * casts object
     * @param Animal $to
     * @return Animal
     */
    public function cast($to)
    {
        parent::cast($to);
        if ($to instanceof Cat) {
            $to->_preferedKindOfFish = $this->_preferedKindOfFish;
        }
        return $to;
    }

    public function getPreferedKindOfFish()
    {
        return $this->_preferedKindOfFish;
    }
}

class Dog extends Animal
{
    private $_preferedKindOfCat = null;

    public function __construct($name = null, $preferedKindOfCat = null)
    {
        parent::__construct($name);
        $this->_preferedKindOfCat = $preferedKindOfCat;
    }

    /**
     * casts object
     * @param Animal $to
     * @return Animal
     */
    public function cast($to)
    {
        parent::cast($to);
        if ($to instanceof Dog) {
            $to->_preferedKindOfCat = $this->_preferedKindOfCat;
        }
        return $to;
    }

    public function getPreferedKindOfCat()
    {
        return $this->_preferedKindOfCat;
    }
}

$dogs = array(
    new Dog('snoopy', 'vegetarian'),
    new Dog('coyote', 'any'),
);

foreach ($dogs as $dog) {
    $cat = $dog->cast(new Cat());
    echo get_class($cat) . ' - ' . $cat->getName() . "\n";
}

回答by Justin

If the object you are trying to cast from or to has properties that are also user-defined classes, and you don't want to go through reflection, you can use this.

如果您尝试从或转换到的对象具有也是用户定义的类的属性,并且您不想通过反射,则可以使用它。

<?php
declare(strict_types=1);
namespace Your\Namespace\Here
{
  use Zend\Logger; // or your logging mechanism of choice
  final class OopFunctions
  {
    /**
     * @param object $from
     * @param object $to
     * @param Logger $logger
     *
     * @return object
     */
     static function Cast($from, $to, $logger)
    {
      $logger->debug($from);
      $fromSerialized = serialize($from);
      $fromName = get_class($from);
      $toName = get_class($to);
      $toSerialized = str_replace($fromName, $toName, $fromSerialized);
      $toSerialized = preg_replace("/O:\d*:\"([^\"]*)/", "O:" . strlen($toName) . ":\"", $toSerialized);
      $toSerialized = preg_replace_callback(
        "/s:\d*:\"[^\"]*\"/", 
        function ($matches)
        {
          $arr = explode(":", $matches[0]);
          $arr[1] = mb_strlen($arr[2]) - 2;
          return implode(":", $arr);
        }, 
        $toSerialized
      );
      $to = unserialize($toSerialized);
      $logger->debug($to);
      return $to;
    }
  }
}

回答by darpet

You do not need casting. Everything is dynamic.

你不需要铸造。一切都是动态的。

I have a class Discount.
I have several classes that extends this class:
ProductDiscount
StoreDiscount
ShippingDiscount
...

我有一个班级折扣。
我有几个扩展这个类的类:
ProductDiscount
StoreDiscount
ShippingDiscount
...

Somewhere in the code I have:

在代码中的某处我有:

$pd = new ProductDiscount();
$pd->setDiscount(5, ProductDiscount::PRODUCT_DISCOUNT_PERCENT);
$pd->setProductId(1);

$this->discounts[] = $pd;

.....

$sd = new StoreDiscount();
$sd->setDiscount(5, StoreDiscount::STORE_DISCOUNT_PERCENT);
$sd->setStoreId(1);

$this->discounts[] = $sd;

And somewhere I have:

在我有的地方:

foreach ($this->discounts as $discount){

    if ($discount->getDiscountType()==Discount::DISCOUNT_TYPE_PRODUCT){

        $productDiscount = $discount; // you do not need casting.
        $amount = $productDiscount->getDiscountAmount($this->getItemTotalPrice());
        ...
    }

}// foreach

Where getDiscountAmount is ProductDiscount specific function, and getDiscountType is Discount specific function.

其中 getDiscountAmount 是 ProductDiscount 特定函数,getDiscountType 是 Discount 特定函数。

回答by KingCrunch

You may think about factories

你可能会想到工厂

class XyFactory {
    public function createXyObject ($other) {
        $new = new XyObject($other->someValue);
        // Do other things, that let $new look like $other (except the used class)
        return $new;
    }
}

Otherwise user250120s solution is the only one, which comes close to class casting.

否则 user250120s 解决方案是唯一一个接近类转换的解决方案。

回答by Elad Elrom

I think that the best approach is to just create a new instance of a class and than assign the object. Here's what I would do:

我认为最好的方法是创建一个类的新实例,而不是分配对象。这是我会做的:

public function ($someVO) {

     $someCastVO = new SomeVO();
     $someCastVO = $someVO;
     $someCastVO->SomePropertyInVO = "123";

}

Doing this will give you code hinting in most IDEs and help ensure you are using the correct properties.

这样做将在大多数 IDE 中为您提供代码提示,并帮助确保您使用正确的属性。

回答by ArthurDent

class It {
    public $a = '';

    public function __construct($a) {
        $this->a = $a;
    }
    public function printIt() {
        ;
    }
}

//contains static function to 'convert' instance of parent It to sub-class instance of Thing

class Thing extends it {
    public $b = '';

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }
    public function printThing() {
        echo $this->a . $this->b;
    }
        //static function housed by target class since trying to create an instance of Thing
    static function thingFromIt(It $it, $b) {
        return new Thing($it->a, $b);
    }
}


//create an instance of It
$it = new It('1');

//create an instance of Thing 
$thing = Thing::thingFromIt($it, '2');


echo 'Class for $it: ' . get_class($it);
echo 'Class for $thing: ' . get_class($thing);

Returns:

返回:

Class for $it: It
Class for $thing: Thing