如何在PHP中转换对象

时间:2010-02-09 01:16:05

标签: php object casting

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

$dog = (Dog) $cat;

是否有可能或有任何通用的工作?

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

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

我从不同的父类继承的类导致我根据保存方法创建了一个继承树,也许从一开始就是我的坏,但问题是我有很多类实际上相同但是与mysql交互一个,与xml文件交互另一个。所以我有:

class MySql_SomeEntity extends SomeMysqlInteract{}

Xml_SomeEntity extends SomeXmlInteract{}

它有点深一点,但问题就在于此。我不能让他们从同一个类继承导致不允许多重继承,并且我不能将当前与超级语言的交互分开导致将是一个大麻烦。

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

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

12 个答案:

答案 0 :(得分:30)

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()复制对象的属性。

This article应该启发你“PHP的黑暗角落”并在用户层面实现类型转换。

答案 1 :(得分:30)

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

答案 2 :(得分:3)

如果不使用继承(如mentioned by author),您似乎正在寻找一种解决方案,可以transform一个类到另一个类,并且开发人员的预先知道并理解2的相似性类

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

答案 3 :(得分:2)

听起来你真正想做的是实现interface

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

答案 4 :(得分:1)

你不需要施法。一切都充满活力。

我有课程折扣 我有几个类扩展了这个类:
ProductDiscount
StoreDiscount
ShippingDiscount
......

我在代码的某处:

$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特定函数。

答案 5 :(得分:1)

更好的方法:

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

答案 6 :(得分:1)

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

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

答案 7 :(得分:0)

您可以考虑工厂

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解决方案是唯一一个接近类强制转换的解决方案。

答案 8 :(得分:0)

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

答案 9 :(得分:0)

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

public function ($someVO) {

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

}

执行此操作将为您提供大多数IDE中的代码提示,并帮助确保您使用正确的属性。

答案 10 :(得分:0)

PHP通过使用以下方法提供了一种非常简单的方法:

(object) ['id'=>1,'name'=>'cat']
  

https://www.php.net/manual/en/language.types.object.php

您可以尝试以下方法:

$dog = json_encode($dog);

$cat = json_decode($dog)

答案 11 :(得分:0)

您可以在下面选择此示例。希望对您有所帮助。

/** @var ClassName $object */

$object->whateverMethod() // any method defined in the class can be accessed by $object

我知道这不是强制转换,但有时可能有用。