2

PHP 5.2.xを使用していて、カスタムPHPクラスのオブジェクトをプライベートメンバーのみでエンコードしたいと考えています。プライベートメンバーの1つは、別のカスタムクラスのオブジェクトの配列です。

https://stackoverflow.com/a/7005915/17716で概説されている解決策を試しましたが、それは明らかに再帰的に機能しません。私が見ることができる唯一の解決策は、json_encodeメソッドを何らかの方法で拡張することです。これにより、デフォルトのメソッドの代わりに、クラスのバージョンのjson_encodeメソッドが呼び出されます。

参考までに、コードは次のとおりです。

Class A {
    private $x;
    private $y;
    private $z;
    private $xy;
    private $yz;
    private $zx;

    public function f1() {
        ...
    }

    public function f2() {
        ...
    }
    .
    .
    .
    public function getJSONEncode() {
         return json_encode(get_object_vars($this));
    }
}

class B {

    private $p; //This finally stores objects of class A
    private $q;
    private $r;

    public function __construct() {
            $this->p = array();
    }

    public function fn1() {
        ...
    }

    public function fn2() {
        ...
    }

    .
    .
    .

    public function getJSONEncode() {
         return json_encode(get_object_vars($this));
    }

}

class C {

    private $arr;

    public function __construct() {
            $this->arr = array();
    }

    public function fillData($data) {
        $obj = new B();
        //create objects of class B and fill in values for all variables
        array_push($this->arr, $obj)
    }

    public function returnData() {
          echo $this->arr[0]->getJSONEncode(); //Edited to add

    }

}

このネストされたjsonエンコーディングを実現するための最良の方法は何でしょうか?

追加するために編集:

returnDataメソッドが実行されたときに得られる出力は次のとおりです。

{"p":[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}],"q":"Lorem Ipsum","r":"Dolor Sit Amet"}
4

1 に答える 1

2

クラスごとに適切なエクスポート/エンコード関数を作成する方がよいと思いますが(エンコードのためだけにプライベート値とパブリック値の両方からパブリックオブジェクトを構築します-非常に賢く、phpのリフレクション機能を使用できます) -代わりに-次のコードを利用できます。

/// example class B
class TestB {
  private $value = 123;
}

/// example class A
class TestA {
  private $prop;
  public function __construct(){
    $this->prop = new TestB();
  }
}

function json_encode_private($obj){
  /// export the variable to find the privates
  $exp = var_export($obj, true);
  /// get rid of the __set_state that only works 5.1+
  $exp = preg_replace('/[a-z0-9_]+\:\:__set_state\(/i','((object)', $exp);
  /// rebuild the object
  eval('$enc = json_encode('.$exp.');');
  /// return the encoded value
  return $enc;
}

echo json_encode_private(new TestA());

/// {"prop":{"value":123}}

したがって、上記は機能するはずですがeval、phpのどこでも使用することはお勧めしません-遠くでアラームベルが静かに鳴るからです:)

アップデート

作成力の一部、または少なくともそれらの力の範囲を制限evalする使用可能なものを使用するのではなく、これを少し安全にする可能性があるものについて考えただけです...create_function

function json_encode_private($obj){
  $exp = var_export($obj, true);
  $exp = preg_replace('/[a-z0-9_]+\:\:__set_state\(/i','((object)', $exp);
  $enc = create_function('','return json_encode('.$exp.');');
  return $enc();
}

アップデート2

単純な関数のみを使用して(evalを使用せずに)、プライベートプロパティを持つオブジェクトをパブリックプロパティを持つオブジェクトに変換する別の方法を試す機会がありました。以下は、使用しているPHPのどのバージョンでもテストする必要があります。これも、変換されたプライベートプロパティのプレフィックスがおかしいため、信頼できない可能性があります(コードのコメントを参照)\0Class Name\0

この奇妙なプレフィックス動作の詳細については、http:
//uk3.php.net/language.types.array.php#language.types.array.castingをご覧ください。

とにかく、テストクラスを使用します。

class RandomClass {
  private $var = 123;
  private $obj;
  public function __construct(){
    $this->obj = (object) null;
    $this->obj->time = time();
  }
}

次の関数を使用して、パブリックオブジェクトに変換できます。

function private_to_public( $a ){
  /// grab our class, convert our object to array, build our return obj
  $c = get_class( $a ); $b = (array) $a; $d = (object) null;
  /// step each property in the array and move over to the object
  /// usually this would be as simple as casting to an object, however
  /// my version of php (5.3) seems to do strange things to private 
  /// properties when casting to an array... hence the code below:
  foreach( $b as $k => $v ){
    /// for some reason private methods are prefixed with a \0 character
    /// and then the classname, followed by \0 before the actual key value. 
    /// This must be some kind of internal protection causing private  
    /// properties to be ignored. \0 is used by some languges to terminate  
    /// strings (not php though, as far as i'm aware).
    if ( ord($k{0}) === 0 ) {
      /// trim off the prefixed weirdnesss..?!
      $e = substr($k, 1 + strlen($c) + 1);
      /// unset the $k var first because it will remember the \0 even 
      /// if other values are assigned to it later on....?!
      unset($k); $k = $e;
    }
    /// so if we have a key, either public or private - set our value on
    /// the destination object.
    if ( $k !== '' && $k !== NULL && $k !== FALSE )  {
      $d->{$k} = $v;
    }
  }
  return $d;
}

したがって、すべてをまとめると、次のようになります。

$a = new RandomClass();

echo json_encode( private_to_public( $a ) );

/// {"var":123,"obj":{"time":1349777323}}

繰り返しになりますが、最善/最も信頼できる方法は、クラスごとに変換メソッドを特注でコーディングするか、Class Reflectionを使用してある種の一般化されたソリューションを作成することですが、後者ははるかに複雑で、StackOverflowの回答よりも複雑です...少なくとも私が自由に使える時間;)

詳細情報

上記のコードは、どこからでもオブジェクトにアクセスしようとしたときに機能します。これを実装する理由は、私の最初の試みが明らかに次のものを使用することだったためです。

echo json_encode( get_object_vars($a) );

/// you will get {} which isn't what you expect

使用したい場合get_object_varsは、すべてのプロパティにアクセスできるコンテキストから、つまり公開しているクラス内から使用する必要があるようです。

public function getAllProperties(){
  return get_object_vars( $this );
}

したがって、上記をRandomClass定義に追加したと想像してください。

echo json_encode( $a->getAllProperties() );

/// you will get {"var":123,"obj":{"time":1349777323}}

これは、クラスのメンバーがパブリックまたはプライベートのすべてのクラスのプロパティにアクセスできるために機能します。つまり、私が言うように、この方法での作業ははるかに優れています。優れていますが、常に可能とは限りません。

于 2012-10-08T17:55:23.183 に答える