Over the past few years JSON has taken over as the king of data interchange formats. Before JSON, XML ruled the roost. It was great at modeling complex data but it is difficult to parse and is very verbose. JSON really took off with the proliferation of rich AJAX driven sites as it’s a very human readable format, quick to parse and its simple key/value representation cuts out all the verbosity of XML.
在过去的几年中,JSON已成为数据交换格式的王者。 在JSON之前,XML是主导。 它非常适合于对复杂数据进行建模,但是很难解析并且非常冗长。 JSON确实随着丰富的AJAX驱动站点的兴起而发展起来,因为它是一种人类可读的格式,可以快速解析,并且其简单的键/值表示法消除了XML的所有冗长性。
I think we could all agree that writing less code that in turn requires less maintenance and introduces less bugs is a goal we would all like to achieve. In this post, I’d like to introduce you to a little known interface that was introduced in PHP 5.4.0 called JsonSerializable
.
我认为我们都可以同意,编写更少的代码反过来需要更少的维护和更少的错误是我们都希望实现的目标。 在本文中,我想向您介绍一个鲜为人知的接口,该接口在PHP 5.4.0中引入了JsonSerializable
。
Before the JsonSerializable interface was available, returning a JSON encoded representation of an object for a consuming service meant one of two things.
在JsonSerializable接口可用之前,为消费服务返回对象的JSON编码表示是两件事之一。
The first approach was to construct a data structure outside the object that contained all the data that we wanted to expose.
第一种方法是在对象外部构造一个数据结构,该数据结构包含我们要公开的所有数据。
email = $email;
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function getEmail()
{
return $this->email;
}
}
$customer = new Customer('[email protected]', 'Joe');
$data = [
'customer' => [
'email' => $customer->getEmail(),
'name' => $customer->getName()
]
];
echo json_encode($data);
We used an array here to hold the data from the Customer
object that we wanted to encode, but it could just as easily have been an StdClass
.
我们在这里使用了一个数组来保存要编码的Customer
对象中的数据,但它很容易成为StdClass
。
This approach was flexible and served its purpose in very simple situations where we knew that the Customer
object wasn’t going to change and we were only going to need Customer
data in this format, in this one place. We also had the option of adding data to this array from other sources if we needed to.
这种方法非常灵活,可以在非常简单的情况下实现其目的,在这种情况下,我们知道Customer
对象不会发生变化,而在这里只需要这种格式的Customer
数据即可。 如果需要,我们还可以选择从其他来源向该阵列添加数据。
However as we’ve all experienced at one time or another, the assumptions we’ve made can be proven false at a moments notice. We might get a requirement that asks us to add more data to the Customer
class. That new data will need to be returned to the consuming service and we’ll want to do this in numerous places.
但是,由于我们一次或两次都经历过,所以我们所做的假设可以立即被证明是错误的。 我们可能会收到要求我们将更多数据添加到Customer
类的要求。 这些新数据将需要返回到使用服务,我们将在许多地方这样做。
As you can imagine, this approach quickly becomes troublesome. Not only do we have to duplicate this array code all over our application, we have to remember to update all those instances when more changes inevitably come in. There is another way though, that will help us nullify some of these issues.
您可以想象,这种方法很快就会变得麻烦。 我们不仅必须在整个应用程序中复制此数组代码,而且还必须记住,不可避免地会有更多更改时更新所有这些实例。不过,还有另一种方法可以帮助我们消除其中的一些问题。
Luckily we were smart when the first change request came in and we realized that duplicating our array was going to be a nightmare, so what we decided to do was internalize that encoding functionality in our object, removing the maintenance issues and reducing the likelihood of introducing bugs.
幸运的是,当第一个更改请求出现时,我们很聪明,我们意识到复制数组将是一场噩梦,所以我们决定要做的是将编码功能内化到我们的对象中,从而消除了维护问题并减少了引入的可能性错误。
email = $email;
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function getEmail()
{
return $this->email;
}
public function toJson()
{
return json_encode([
'customer' => [
'email' => $this->getEmail(),
'name' => $this->getName()
]
]);
}
}
$customer = new Customer('[email protected]', 'Joe');
echo $customer->toJson();
Now if any more change requests come in that want more data to be added to and returned from the Customer
object we can just update the toJson
method.
现在,如果有更多更改请求要添加到Customer
对象中并从其中返回,我们可以仅更新toJson
方法。
This approach has it’s own drawbacks, though. Anyone else that comes along and wants to use our Customer
needs to be aware of this toJson
method because it’s not something that is easily checked for, so we’d need accurate documentation. We also have to remember that this method returns JSON now, (though we could move the serialization outside the method). This makes combining Customer
data with other sources of data more awkward because we have to be careful not to encode the result of this method again as that would cause some nasty bugs.
但是,这种方法有其自身的缺点。 想要使用我们的Customer
其他任何人都需要知道此toJson
方法,因为它不是很容易检查的东西,因此我们需要准确的文档。 我们还必须记住,此方法现在返回 JSON(尽管我们可以将序列化移到该方法之外)。 这使得将Customer
数据与其他数据源组合起来更加尴尬,因为我们必须小心,不要再次对该方法的结果进行编码,因为这会导致一些讨厌的错误。
Finally, enter the JsonSerializable
interface. This gives us all the flexibility of the Ugly scenario with the maintainability benefits of the Bad scenario. Though to use this interface you will need to be running PHP 5.4.0+ which you really should be doing anyway, as there are many improvements over older versions.
最后,进入JsonSerializable
接口。 这给我们带来了丑陋场景的所有灵活性,以及糟糕场景的可维护性。 尽管要使用此接口,您将需要运行PHP 5.4.0+,无论如何,您确实应该这样做,因为相对于旧版本有很多改进。
So, to business.
所以,要生意。
name = $name;
$this->email = $email;
}
public function getName()
{
return $this->name;
}
public function getEmail()
{
return $this->email;
}
public function jsonSerialize()
{
return [
'customer' => [
'name' => $this->name,
'email' => $this->email
]
];
}
}
$customer = new Customer('[email protected]', 'Joe');
echo json_encode($customer);
As you can see, we implement JsonSerializable
by adding the interface to our class and then adding a jsonSerialize
method to the body of our class to satisfy the interfaces contract.
如您所见,我们通过将接口添加到我们的类中,然后在我们的类的主体中添加一个jsonSerialize
方法来实现JsonSerializable
,以满足接口协定。
In the jsonSerialize
method we construct and return an array of the object data, just as we did with the other examples. Once again if anything changes then we can just update this one method. You’ll notice that the jsonSerialize
method just returns an array.
就像其他示例一样,在jsonSerialize
方法中,我们构造并返回对象数据的数组。 再说一次,如果有什么变化,我们可以更新这一方法。 您会注意到jsonSerialize
方法仅返回一个数组。
The magic comes when you want to trigger this method, all we have to do now is json encode an instance of this class and this method will be called automatically, the array of data returned and then encoded! Now that the class implements an interface we benefit from being able to check if this class is an instanceof JsonSerializable
. If you wanted you could also type hint in methods to make sure a JsonSerializable
interface is passed.
当您想触发此方法时,魔术就来了,我们现在要做的就是对此类的实例进行json编码,并且此方法将被自动调用,返回数据数组然后进行编码! 现在,该类实现了接口,我们将从能够检查该类是否为JsonSerializable
的实例中JsonSerializable
。 如果需要,还可以在方法中键入提示以确保传递了JsonSerializable
接口。
With this simple implementation, we’ve removed duplication, decreased the amount of maintenance and reduced the chances of introducing bugs. We’ve also made it trivial for another person using our code to test for the ability of the object to be encoded by checking if it’s an instance of JsonSerializable
.
通过这种简单的实现,我们消除了重复,减少了维护量,并减少了引入错误的机会。 通过检查代码是否是JsonSerializable
实例,我们也使其他人使用我们的代码来测试对象的编码能力JsonSerializable
。
The examples above are of course contrived, however, I hope I’ve managed to demonstrate the benefits of using this interface and inspire you to go ahead and use it yourself.
上面的示例当然是人为设计的,但是,我希望我已经设法证明了使用此界面的好处,并激发您继续使用该界面。
翻译自: https://www.sitepoint.com/use-jsonserializable-interface/