Có thể giải mã chuỗi json thành một đối tượng khác với stdClass không?
Có thể giải mã chuỗi json thành một đối tượng khác với stdClass không?
Câu trả lời:
Không tự động. Nhưng bạn có thể làm theo cách cũ.
$data = json_decode($json, true);
$class = new Whatever();
foreach ($data as $key => $value) $class->{$key} = $value;
Hoặc cách khác, bạn có thể làm cho điều đó tự động hơn:
class Whatever {
public function set($data) {
foreach ($data AS $key => $value) $this->{$key} = $value;
}
}
$class = new Whatever();
$class->set($data);
Chỉnh sửa : nhận được một chút huyền ảo:
class JSONObject {
public function __construct($json = false) {
if ($json) $this->set(json_decode($json, true));
}
public function set($data) {
foreach ($data AS $key => $value) {
if (is_array($value)) {
$sub = new JSONObject;
$sub->set($value);
$value = $sub;
}
$this->{$key} = $value;
}
}
}
// These next steps aren't necessary. I'm just prepping test data.
$data = array(
"this" => "that",
"what" => "who",
"how" => "dy",
"multi" => array(
"more" => "stuff"
)
);
$jsonString = json_encode($data);
// Here's the sweetness.
$class = new JSONObject($jsonString);
print_r($class);
Chúng tôi đã xây dựng JsonMapper để tự động ánh xạ các đối tượng JSON vào các lớp mô hình của riêng chúng tôi. Nó hoạt động tốt với các đối tượng lồng nhau / con.
Nó chỉ dựa vào thông tin loại docblock để ánh xạ, mà hầu hết các thuộc tính của lớp đều có:
<?php
$mapper = new JsonMapper();
$contactObject = $mapper->map(
json_decode(file_get_contents('http://example.org/contact.json')),
new Contact()
);
?>
Bạn có thể làm được - đó là một điều khó nhưng hoàn toàn có thể. Chúng tôi phải làm khi bắt đầu lưu trữ mọi thứ trong couchbase.
$stdobj = json_decode($json_encoded_myClassInstance); //JSON to stdClass
$temp = serialize($stdobj); //stdClass to serialized
// Now we reach in and change the class of the serialized object
$temp = preg_replace('@^O:8:"stdClass":@','O:7:"MyClass":',$temp);
// Unserialize and walk away like nothing happend
$myClassInstance = unserialize($temp); // Presto a php Class
Trong các điểm chuẩn của chúng tôi, cách này nhanh hơn so với việc cố gắng lặp qua tất cả các biến lớp.
Lưu ý: Sẽ không hoạt động đối với các đối tượng lồng nhau ngoài stdClass
Chỉnh sửa: hãy ghi nhớ nguồn dữ liệu, bạn không nên làm điều này với dữ liệu không đáng tin cậy từ người dùng mà không có phân tích cẩn thận về rủi ro.
{ "a": {"b":"c"} }
trong đó đối tượng thuộc a
một lớp khác chứ không chỉ là một mảng kết hợp?
Bạn có thể sử dụng thư viện Serializer của J ohannes Schmitt .
$serializer = JMS\Serializer\SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, 'MyNamespace\MyObject', 'json');
Trong phiên bản mới nhất của bộ tuần tự JMS, cú pháp là:
$serializer = SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, MyObject::class, 'json');
::class
ký hiệu: php.net/manual/en/...
Bạn có thể tạo một trình bao bọc cho đối tượng của mình và làm cho trình bao bọc trông giống như chính nó là đối tượng. Và nó sẽ hoạt động với các đối tượng đa cấp.
<?php
class Obj
{
public $slave;
public function __get($key) {
return property_exists ( $this->slave , $key ) ? $this->slave->{$key} : null;
}
public function __construct(stdClass $slave)
{
$this->slave = $slave;
}
}
$std = json_decode('{"s3":{"s2":{"s1":777}}}');
$o = new Obj($std);
echo $o->s3->s2->s1; // you will have 777
Không, điều này là không thể với PHP 5.5.1.
Điều duy nhất có thể là có json_decode
các mảng liên kết trả về thay vì các đối tượng StdClass.
Bạn có thể thực hiện theo cách dưới đây ..
<?php
class CatalogProduct
{
public $product_id;
public $sku;
public $name;
public $set;
public $type;
public $category_ids;
public $website_ids;
function __construct(array $data)
{
foreach($data as $key => $val)
{
if(property_exists(__CLASS__,$key))
{
$this->$key = $val;
}
}
}
}
?>
Để biết thêm chi tiết, hãy truy cập create-custom-class-in-php-from-json-or-array
Tôi ngạc nhiên là chưa có ai đề cập đến điều này.
Sử dụng thành phần Symfony Serializer: https://symfony.com/doc/current/components/serializer.html
Sắp xếp thứ tự từ Object sang JSON:
use App\Model\Person;
$person = new Person();
$person->setName('foo');
$person->setAge(99);
$person->setSportsperson(false);
$jsonContent = $serializer->serialize($person, 'json');
// $jsonContent contains {"name":"foo","age":99,"sportsperson":false,"createdAt":null}
echo $jsonContent; // or return it in a Response
Hủy số liệu hóa từ JSON sang Đối tượng: (ví dụ này sử dụng XML chỉ để chứng minh tính linh hoạt của các định dạng)
use App\Model\Person;
$data = <<<EOF
<person>
<name>foo</name>
<age>99</age>
<sportsperson>false</sportsperson>
</person>
EOF;
$person = $serializer->deserialize($data, Person::class, 'xml');
Sử dụng phản chiếu :
function json_decode_object(string $json, string $class)
{
$reflection = new ReflectionClass($class);
$instance = $reflection->newInstanceWithoutConstructor();
$json = json_decode($json, true);
$properties = $reflection->getProperties();
foreach ($properties as $key => $property) {
$property->setAccessible(true);
$property->setValue($instance, $json[$property->getName()]);
}
return $instance;
}
Như Gordon nói là không thể. Nhưng nếu bạn đang tìm cách lấy một chuỗi có thể được giải mã dưới dạng một thể hiện của lớp give, bạn có thể sử dụng serialize và unserialize để thay thế.
class Foo
{
protected $bar = 'Hello World';
function getBar() {
return $this->bar;
}
}
$string = serialize(new Foo);
$foo = unserialize($string);
echo $foo->getBar();
Tôi đã từng tạo một lớp cơ sở trừu tượng cho mục đích này. Hãy gọi nó là JsonConvertible. Nó sẽ tuần tự hóa và giải mã hóa các thành viên công cộng. Điều này có thể thực hiện được bằng cách sử dụng Phản chiếu và liên kết tĩnh muộn.
abstract class JsonConvertible {
static function fromJson($json) {
$result = new static();
$objJson = json_decode($json);
$class = new \ReflectionClass($result);
$publicProps = $class->getProperties(\ReflectionProperty::IS_PUBLIC);
foreach ($publicProps as $prop) {
$propName = $prop->name;
if (isset($objJson->$propName) {
$prop->setValue($result, $objJson->$propName);
}
else {
$prop->setValue($result, null);
}
}
return $result;
}
function toJson() {
return json_encode($this);
}
}
class MyClass extends JsonConvertible {
public $name;
public $whatever;
}
$mine = MyClass::fromJson('{"name": "My Name", "whatever": "Whatever"}');
echo $mine->toJson();
Chỉ từ trí nhớ, vì vậy có lẽ không hoàn hảo. Bạn cũng sẽ phải loại trừ các thuộc tính tĩnh và có thể cho các lớp dẫn xuất cơ hội để làm cho một số thuộc tính bị bỏ qua khi tuần tự hóa đến / từ json. Tôi hy vọng bạn có được ý tưởng, dù sao.
JSON là một giao thức đơn giản để truyền dữ liệu giữa các ngôn ngữ lập trình khác nhau (và nó cũng là một tập hợp con của JavaScript) chỉ hỗ trợ một số kiểu nhất định: số, chuỗi, mảng / danh sách, đối tượng / dicts. Đối tượng chỉ là bản đồ key = value và Mảng là danh sách có thứ tự.
Vì vậy, không có cách nào để thể hiện các đối tượng tùy chỉnh một cách chung chung. Giải pháp là xác định một cấu trúc mà (các) chương trình của bạn sẽ biết rằng đó là một đối tượng tùy chỉnh.
Đây là một ví dụ:
{ "cls": "MyClass", fields: { "a": 123, "foo": "bar" } }
Điều này có thể được sử dụng để tạo một phiên bản của MyClass
và đặt các trường a
và foo
đến 123
và "bar"
.
Tôi đã tiếp tục và triển khai câu trả lời của John Petit , dưới dạng một hàm ( ý chính ):
function json_decode_to(string $json, string $class = stdClass::class, int $depth = 512, int $options = 0)
{
$stdObj = json_decode($json, false, $depth, $options);
if ($class === stdClass::class) return $stdObj;
$count = strlen($class);
$temp = serialize($stdObj);
$temp = preg_replace("@^O:8:\"stdClass\":@", "O:$count:\"$class\":", $temp);
return unserialize($temp);
}
Điều này hoạt động hoàn hảo cho trường hợp sử dụng của tôi. Tuy nhiên , câu trả lời của Yevgeniy Afanasyev có vẻ hứa hẹn không kém đối với tôi. Có thể có lớp của bạn có thêm một "hàm tạo", như sau:
public static function withJson(string $json) {
$instance = new static();
// Do your thing
return $instance;
}
Đây cũng là cảm hứng từ câu trả lời này .