Nice programing

PHP에서 개체를 캐스팅하는 방법

nicepro 2020. 12. 25. 22:57
반응형

PHP에서 개체를 캐스팅하는 방법


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

$dog = (Dog) $cat;

가능합니까 아니면 일반적인 해결 방법이 있습니까?

수퍼 클래스도 아니고 인터페이스도 아니고 어떤 식 으로든 관련이 있습니다. 그들은 단지 2 개의 다른 클래스입니다. php는 고양이 클래스의 속성을 개로 매핑하고 새 개체를 제공하고 싶습니다.

나는 조금 더 원인을 지정해야 할 것 같아 무의미한 일처럼 보입니다.

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

class MySql_SomeEntity extends SomeMysqlInteract{}

Xml_SomeEntity extends SomeXmlInteract{}

조금 더 깊은 나무이지만 문제는 그것입니다. 여러 상속이 허용되지 않기 때문에 동일한 클래스에서 상속받을 수 없으며 현재 상호 작용을 superclases와 분리하면 큰 문제가 될 것입니다.

기본적으로 각각의 속성은 실용적입니다.

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


유사하지 않은 클래스 객체를 캐스팅하기 위해 위의 함수를 사용할 수 있습니다 (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에서 사용자 정의 객체의 타입 캐스팅을위한 내장 방법은 없습니다. 즉, 다음과 같은 몇 가지 가능한 솔루션이 있습니다.

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의 어두운 구석"에 대해 설명하고 사용자 수준에서 형변환을 구현해야합니다.


상속을 사용하지 않고 ( author 에서 언급했듯이 ) 개발자가 두 클래스의 유사성을 알고 이해한다는 가정하에transform 한 클래스에서 다른 클래스로 이동할 수있는 솔루션을 찾고있는 것 같습니다 .

개체 간 변환을위한 기존 솔루션이 없습니다. 시도해 볼 수있는 것은 다음과 같습니다.


당신이 정말로 원하는 것은 인터페이스를 구현하는 것 같습니다 .

인터페이스는 객체가 처리 할 수있는 메소드를 지정하고 인터페이스를 지원하는 객체를 원하는 메소드에 인터페이스를 구현하는 객체를 전달할 때 인터페이스 이름과 함께 인수를 입력하기 만하면됩니다.


캐스팅이 필요하지 않습니다. 모든 것이 역동적입니다.

클래스 할인이 있습니다.
이 클래스를 확장하는 여러 클래스가 있습니다.
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은 할인 특정 함수입니다.


더 나은 앞치마 :

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

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

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

공장에 대해 생각할 수 있습니다

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에서 코드 힌트가 제공되고 올바른 속성을 사용하고 있는지 확인하는 데 도움이됩니다.

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

반응형