如何在PHP中转换对象

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

$dog = (Dog) $cat;

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

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

我想我必须指定更多原因,这似乎是一件毫无意义的事情。

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

class MySql_SomeEntity extends SomeMysqlInteract{}

Xml_SomeEntity extends SomeXmlInteract{}

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

基本上,每个属性都是实用的。

由于我有很多此类匹配类,因此我想进行一些通用的转换或类似的转换(可以将值传递给每个属性),但是我想尝试以最简单的方式搜索此类中的每个类。

user267599 asked 2019-11-08T04:03:49Z
10个解决方案
30 votes

您可以使用上面的函数来转换不相似的类对象(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;
}

例:

class A 
{
  private $_x;   
}

class B 
{
  public $_x;   
}

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

$x = cast('A',$b);
$x = cast('B',$a);
Adam Puza answered 2019-11-08T04:03:57Z
30 votes

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

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)或者,您可以使用反射/手动遍历所有对象或使用get_object_vars()复制对象的属性。

本文将带您进入“ PHP的黑暗角落”,并在用户级别实现类型转换。

user250120 answered 2019-11-08T04:04:40Z
3 votes

不使用继承(如作者所提及),似乎您正在寻找一种解决方案,可以在开发人员预先假设的情况下将transform的一个类转换为另一个类,从而了解并理解2个类的相似性。

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

  • get_object_vars():将对象转换为数组
  • 转换为对象:将数组转换为对象
Trav L answered 2019-11-08T04:05:24Z
3 votes

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

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

Matthew Sturges answered 2019-11-08T04:05:54Z
1 votes

您不需要强制转换。 一切都是动态的。

我有全班折扣。
我有几个扩展此类的类:
产品折扣
商店折扣
运费折扣
...

我在代码中的某个地方:

$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;

我有一个地方:

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

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

darpet answered 2019-11-08T04:07:16Z
1 votes

更好的方法:

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";
}
useless answered 2019-11-08T04:07:39Z
1 votes

如果您要投射或投射的对象具有也是用户定义类的属性,并且不想进行反射,则可以使用此属性。

<?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) . ":\"$1", $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;
    }
  }
}
Justin answered 2019-11-08T04:08:03Z
0 votes

您可能会想到工厂

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;
    }
}

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

KingCrunch answered 2019-11-08T04:08:32Z
0 votes
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);

返回值:

Class for $it: It
Class for $thing: Thing
ArthurDent answered 2019-11-08T04:08:56Z
0 votes

我认为最好的方法是仅创建类的新实例,然后分配对象。 这就是我要做的:

public function ($someVO) {

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

}

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

Elad Elrom answered 2019-11-08T04:09:27Z
translate from https://stackoverflow.com:/questions/2226103/how-to-cast-objects-in-php