programing

PHP에서 오브젝트를 캐스트하는 방법

yellowcard 2023. 9. 27. 17:42
반응형

PHP에서 오브젝트를 캐스트하는 방법

몇 가지 속성을 공유하는 클래스가 있는데 다음과 같은 작업을 수행하고 싶습니다.

$dog = (Dog) $cat;

가능한가요, 아니면 일반적인 작업이 가능한가요?

그것은 슈퍼클래스, 인터페이스 또는 어떤 식으로든 연관된 것이 아닙니다.단지 2개의 클래스가 다를 뿐입니다. 고양이 클래스의 속성을 개로 pph 매핑하여 새로운 객체를 주고 싶습니다. -

좀 더 구체적으로 설명해야 할 것 같아요. 무의미한 일인 것 같아요.

저장 방법을 기반으로 상속 트리를 만들었기 때문에 다른 부모 클래스에서 상속되는 클래스가 있습니다. 처음부터 잘못되었을 수도 있지만 문제는 실질적으로 동일하지만 하나는 mysql과, 다른 하나는 xml 파일과 상호 작용하는 클래스가 많다는 것입니다.그래서 나는 다음을 가지고 있습니다.

class MySql_SomeEntity extends SomeMysqlInteract{}

그리고.

Xml_SomeEntity extends SomeXmlInteract{}

트리가 조금 더 깊지만 문제는 그것입니다. 다중 상속이 허용되지 않기 때문에 동일한 클래스에서 상속하도록 할 수 없고 현재 상호 작용과 슈퍼 클래스를 분리할 수 없기 때문에 큰 문제가 될 것입니다.

기본적으로 각각의 속성은 실제적으로 동일합니다.

이 일치하는 클래스가 많기 때문에 변환(각 속성에 값 전달)할 수 있는 일반 캐스팅 등을 수행하고 싶지만 이 클래스의 모든 사람에게 가장 간단한 방법을 검색하려고 합니다.

유사하지 않은 클래스 객체를 주조할 때 위의 기능을 사용할 수 있습니다(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);

PHP에는 사용자 정의 개체의 type casting을 위한 기본 제공 방법이 없습니다.그럼에도 불구하고, 다음과 같은 몇 가지 가능한 해결책이 있습니다.

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) 또는 reflection / 수동으로 모두 반복하거나 get_object_vars()를 사용하여 개체의 속성을 복사할 수도 있습니다.

이 글은 "PHP의 어두운 구석"과 사용자 수준에서 유형 캐스팅을 구현하는 것에 대해 여러분에게 알려줄 것입니다.

(저자가 언급한 대로) 상속을 사용하지 않고 다음과 같이 할 수 있는 해결책을 찾고 있는 것 같습니다.transform개발자의 가정하에 한 클래스에서 다른 클래스로 2 클래스의 유사성을 알고 이해합니다.

객체 간의 변환을 위한 기존의 해결책은 없습니다.시도해 볼 수 있는 것은 다음과 같습니다.

캐스팅은 필요 없습니다.모든 것이 역동적입니다.

할인 수업이 있습니다.
는 이 하는 몇 다.


할인
...

내가 가지고 있는 코드 어딘가에:

$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특정기능입니다.

더 나은 접근법:

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

당신이 정말로 하고 싶은 것은 인터페이스를 구현하는 것처럼 들립니다.

인터페이스는 개체가 처리할 수 있는 메서드를 지정하고 인터페이스를 지원하는 개체를 원하는 메서드에 인터페이스를 구현하는 개체를 전달할 때 인터페이스 이름으로 인수를 입력하면 됩니다.

공장에 대해 생각해 볼 수도 있습니다.

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 솔루션이 유일합니다.

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

저는 클래스의 새로운 인스턴스를 만들고 객체를 할당하는 것보다 더 나은 방법이라고 생각합니다.제가 할 수 있는 일은 이렇습니다.

public function ($someVO) {

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

}

이렇게 하면 대부분의 IDE에서 코드 힌트를 얻을 수 있고 올바른 속성을 사용하고 있는지 확인하는 데 도움이 됩니다.

캐스트하려는 개체 또는 캐스트할 개체에 사용자 정의 클래스인 속성이 있고 리플렉션을 거치지 않으려면 이 개체를 사용할 수 있습니다.

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

아래 예를 선택할 수 있습니다.도움이 되길 바랍니다.

/** @var ClassName $object */

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

깁스가 아닌 건 알지만 가끔은 유용할 수도 있습니다.

PHP는 다음을 사용하여 매우 간단한 방법을 제공합니다.

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

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

사용자의 경우 다음을 시도합니다.

$dog = json_encode($dog);

$cat = (object) json_decode($dog)

보다 최적화된 방법은 다음과 같습니다.

$dog = (array)$dog;
$dog['newfield'] = 'xyz';
$dog = (object)$dog;

언급URL : https://stackoverflow.com/questions/2226103/how-to-cast-objects-in-php

반응형