97

私はサードパーティのストレージ システムを使用しています。このシステムは、なんらかの理由で何をフィードしても stdClass オブジェクトのみを返します。そのため、stdClass オブジェクトを特定の型の本格的なオブジェクトにキャスト/変換する方法があるかどうかを知りたいと思っています。

たとえば、次のようなものがあります。

//$stdClass is an stdClass instance
$converted = (BusinessClass) $stdClass;

stdClass を配列にキャストして BusinessClass コンストラクターにフィードしているだけですが、私が認識していない初期クラスを復元​​する方法があるかもしれません。

注: 「ストレージ システムの変更」タイプの回答には興味がありません。これは重要な点ではないためです。言語能力に関するアカデミックな問題と考えてください。

乾杯

4

11 に答える 11

94

可能なキャストについては、Type Jugglingのマニュアルを参照してください。

許可されているキャストは次のとおりです。

  • (int), (integer) - 整数にキャスト
  • (bool), (boolean) - ブール値にキャスト
  • (float), (double), (real) - float にキャスト
  • (文字列) - 文字列にキャスト
  • (配列) - 配列にキャスト
  • (オブジェクト) - オブジェクトにキャスト
  • (未設定) - NULL にキャスト (PHP 5)

stdClass から別の具象クラスへのキャストを行う Mapperを作成する必要があります。難しすぎてはいけません。

または、ハック気分の場合は、次のコードを変更できます。

function arrayToObject(array $array, $className) {
    return unserialize(sprintf(
        'O:%d:"%s"%s',
        strlen($className),
        $className,
        strstr(serialize($array), ':')
    ));
}

これは、配列を特定のクラスのオブジェクトに疑似キャストします。これは、最初に配列をシリアライズしてから、特定のクラスを表すようにシリアライズされたデータを変更することで機能します。結果は、このクラスのインスタンスに非シリアル化されます。しかし、私が言ったように、それはハックなので、副作用を期待してください.

オブジェクト対オブジェクトの場合、コードは次のようになります。

function objectToObject($instance, $className) {
    return unserialize(sprintf(
        'O:%d:"%s"%s',
        strlen($className),
        $className,
        strstr(strstr(serialize($instance), '"'), ':')
    ));
}
于 2010-07-14T06:54:33.680 に答える
55

類似していないクラスオブジェクトをキャストするために上記の関数を使用できます (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);
于 2012-03-21T20:08:53.510 に答える
16

の既存のすべてのプロパティをstdClass、指定したクラス名の新しいオブジェクトに移動するには:

/**
 * recast stdClass object to an object with type
 *
 * @param string $className
 * @param stdClass $object
 * @throws InvalidArgumentException
 * @return mixed new, typed object
 */
function recast($className, stdClass &$object)
{
    if (!class_exists($className))
        throw new InvalidArgumentException(sprintf('Inexistant class %s.', $className));

    $new = new $className();

    foreach($object as $property => &$value)
    {
        $new->$property = &$value;
        unset($object->$property);
    }
    unset($value);
    $object = (unset) $object;
    return $new;
}

使用法:

$array = array('h','n');

$obj=new stdClass;
$obj->action='auth';
$obj->params= &$array;
$obj->authKey=md5('i');

class RestQuery{
    public $action;
    public $params=array();
    public $authKey='';
}

$restQuery = recast('RestQuery', $obj);

var_dump($restQuery, $obj);

出力:

object(RestQuery)#2 (3) {
  ["action"]=>
  string(4) "auth"
  ["params"]=>
  &array(2) {
    [0]=>
    string(1) "h"
    [1]=>
    string(1) "n"
  }
  ["authKey"]=>
  string(32) "865c0c0b4ab0e063e5caa3387c1a8741"
}
NULL

newこれは、オペレーターが必要とするパラメーターが不明であるため、オペレーターによって制限されます。あなたの場合、おそらく適切です。

于 2012-01-20T19:10:08.550 に答える
12

私は非常によく似た問題を抱えています。単純化されたリフレクション ソリューションは、私にとってはうまく機能しました。

public static function cast($destination, \stdClass $source)
{
    $sourceReflection = new \ReflectionObject($source);
    $sourceProperties = $sourceReflection->getProperties();
    foreach ($sourceProperties as $sourceProperty) {
        $name = $sourceProperty->getName();
        $destination->{$name} = $source->$name;
    }
    return $destination;
}
于 2012-08-28T12:29:22.010 に答える
10

誰かがこれが役に立つことを願っています

// new instance of stdClass Object
$item = (object) array(
    'id'     => 1,
    'value'  => 'test object',
);

// cast the stdClass Object to another type by passing
// the value through constructor
$casted = new ModelFoo($item);

// OR..

// cast the stdObject using the method
$casted = new ModelFoo;
$casted->cast($item);
class Castable
{
    public function __construct($object = null)
    {
        $this->cast($object);
    }

    public function cast($object)
    {
        if (is_array($object) || is_object($object)) {
            foreach ($object as $key => $value) {
                $this->$key = $value;
            }
        }
    }
} 
class ModelFoo extends Castable
{
    public $id;
    public $value;
}
于 2014-12-12T11:46:37.570 に答える