Search code examples
phpjsonsymfonydeserializationsymfony-serializer

PHP Symfony parse JSON response deserialize class constructor


I am trying to parse this JSON $response body = {"low":{"networkFee":"0.00003"},"medium":{"networkFee":"0.0000428"},"high":{"networkFee":"0.00024"}}

my code:

class Low {
  private $networkFee;
}
class Medium {
  private $networkFee;
}
class High {
  private $networkFee;
}
class FeeClass{ 
  public function __construct(Low $low, Medium $medium, High $high) {
    $this->low = $low;
    $this->medium = $medium;
    $this->high = $high;
  }
}
$encoders = [new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer( $normalizers, $encoders );

$parsed = $serializer->deserialize((string)$response->getBody(), FeeClass::class, 'json');

var_dump("parsed:", $parsed);//I only get 3 NULL in $parsed

My dependencies:

"laravel/framework": "6.20.x",
"symfony/serializer": "5.1.x",

Solution

  • A possibility is to make the $networkFee property public for Low, Medium and High:

    require 'vendor/autoload.php';
    
    use Symfony\Component\Serializer\Encoder\JsonEncoder;
    use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
    use Symfony\Component\Serializer\Serializer;
    
    class Low {
      public $networkFee;
    }
    
    class Medium {
      public $networkFee;
    }
    
    class High {
      public $networkFee;
    }
    
    class FeeClass {
      private Low $low;
      private Medium $medium;
      private High $high;
    
      public function __construct(Low $low, Medium $medium, High $high) {
        $this->low = $low;
        $this->medium = $medium;
        $this->high = $high;
      }
    }
    
    $json = '{"low":{"networkFee":"0.00003"},"medium":{"networkFee":"0.0000428"},"high":{"networkFee":"0.00024"}}';
    
    $encoders = [new JsonEncoder()];
    $normalizers = [new ObjectNormalizer()];
    $serializer = new Serializer( $normalizers, $encoders );
    $parsed = $serializer->deserialize($json, FeeClass::class, 'json');
    var_dump($parsed);
    

    Output:

    object(FeeClass)#31 (3) {
      ["low":"FeeClass":private]=>
      object(Low)#38 (1) {
        ["networkFee"]=>
        string(7) "0.00003"
      }
      ["medium":"FeeClass":private]=>
      object(Medium)#33 (1) {
        ["networkFee"]=>
        string(9) "0.0000428"
      }
      ["high":"FeeClass":private]=>
      object(High)#37 (1) {
        ["networkFee"]=>
        string(7) "0.00024"
      }
    }
    

    Alternatively you can add public constructors to Low, Medium and High:

    class Low {
      private $networkFee;
    
      public function __construct($networkFee) {
          $this->networkFee = $networkFee;
      }
    }
    
    class Medium {
      private $networkFee;
    
      public function __construct($networkFee) {
          $this->networkFee = $networkFee;
      }
    }
    
    class High {
      private $networkFee;
    
      public function __construct($networkFee) {
          $this->networkFee = $networkFee;
      }
    }