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
한 클래스에서 다른 클래스로 이동할 수있는 솔루션을 찾고있는 것 같습니다 .
개체 간 변환을위한 기존 솔루션이 없습니다. 시도해 볼 수있는 것은 다음과 같습니다.
- get_object_vars () : 객체를 배열로 변환
- Cast to Object : 배열을 객체로 변환
당신이 정말로 원하는 것은 인터페이스를 구현하는 것 같습니다 .
인터페이스는 객체가 처리 할 수있는 메소드를 지정하고 인터페이스를 지원하는 객체를 원하는 메소드에 인터페이스를 구현하는 객체를 전달할 때 인터페이스 이름과 함께 인수를 입력하기 만하면됩니다.
캐스팅이 필요하지 않습니다. 모든 것이 역동적입니다.
클래스 할인이 있습니다.
이 클래스를 확장하는 여러 클래스가 있습니다.
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
'Nice programing' 카테고리의 다른 글
Tomcat 6을 삽입하는 방법? (0) | 2020.12.25 |
---|---|
cmd.exe에서 "배치 작업 종료"를 억제하려면 어떻게해야합니까? (0) | 2020.12.25 |
자바 스크립트를 사용하여 헤드를 포함한 전체 페이지 교체 (0) | 2020.12.25 |
"오류 : MyClass 클래스에서 Main 메서드를 찾을 수 없습니다. main 메서드를 다음과 같이 정의하십시오…" (0) | 2020.12.25 |
분기 이름에 '공백'문자가 포함될 수없는 이유는 무엇입니까? (0) | 2020.12.25 |