Статьи

Как использовать интерфейс JsonSerializable

За последние несколько лет JSON стал королем форматов обмена данными. До JSON XML правил рутом. Он был великолепен при моделировании сложных данных, но его трудно анализировать и он очень многословен JSON действительно вырос с распространением богатых сайтов, управляемых AJAX, так как это очень удобный для восприятия формат, быстрый анализ, а его простое представление ключ / значение исключает всю многословность XML.

Я думаю, что мы все могли бы согласиться с тем, что написание меньшего количества кода, которое в свою очередь требует меньшего количества обслуживания и вносит меньше ошибок, является целью, которую мы все хотели бы достичь В этой статье я хотел бы познакомить вас с малоизвестным интерфейсом, который был представлен в PHP 5.4.0 и называется JsonSerializable .

До того, как интерфейс JsonSerializable был доступен, возвращение JSON-закодированного представления объекта для потребляющего сервиса означало одно из двух.

Гадкий

Первый подход заключался в создании структуры данных вне объекта, которая содержала все данные, которые мы хотели представить

 <? php class   Customer 
 { 

     private  $email =   null ; 
     private  $name =   null ; 

     public   function  __construct ( $email ,  $name ) 
     { $this -> 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 ); 

Мы использовали здесь массив для хранения данных из объекта Customer который мы хотели закодировать, но это также мог быть StdClass .

Этот подход был гибким и служил своей цели в очень простых ситуациях, когда мы знали, что объект Customer не изменится, и нам нужны только данные Customer в этом формате, в одном месте. У нас также была возможность добавлять данные в этот массив из других источников, если это было необходимо.

Однако, поскольку мы все пережили то или иное время, сделанные нами предположения могут быть подтверждены ложно в любой момент. Возможно, мы получим требование добавить больше данных в класс Customer . Эти новые данные необходимо будет вернуть потребителю, и мы хотим сделать это во многих местах.

Как вы можете себе представить, такой подход быстро становится проблематичным. Мы не только должны дублировать этот код массива по всему нашему приложению, мы также должны помнить, что нужно обновлять все эти случаи, когда неизбежно появляются дополнительные изменения. Однако есть и другой способ, который поможет нам устранить некоторые из этих проблем.

Плохо

К счастью, мы были умны, когда поступил первый запрос на изменение, и мы поняли, что дублирование нашего массива станет кошмаром, поэтому мы решили внедрить эту функциональность кодирования в нашем объекте, устраняя проблемы обслуживания и уменьшая вероятность внедрения ошибок.

 <? php class   Customer 
 { 

     public  $email =   null ; 
     public  $name =   null ; 

     public   function  __construct ( $email ,  $name ) 
     { $this -> 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 (); 

Теперь, если поступают еще какие-либо запросы на изменение, требующие добавления и возврата дополнительных данных из объекта Customer мы можем просто обновить метод toJson .

Этот подход имеет свои недостатки, однако. Любой, кто придет и захочет использовать нашего Customer должен знать об этом методе toJson потому что это не то, что легко проверяется, поэтому нам нужна точная документация. Мы также должны помнить, что этот метод теперь возвращает JSON (хотя мы могли бы вывести сериализацию за пределы метода). Это усложняет объединение данных Customer с другими источниками данных, потому что мы должны быть осторожны, чтобы не закодировать результат этого метода снова, так как это может вызвать некоторые неприятные ошибки.

Хорошо

Наконец, войдите в интерфейс JsonSerializable . Это дает нам всю гибкость сценария Ugly с преимуществами обслуживания в сценарии Bad . Хотя, чтобы использовать этот интерфейс, вам нужно будет запустить PHP 5.4.0+, который вы действительно должны делать в любом случае, поскольку есть много улучшений по сравнению со старыми версиями.

Итак, к делу.

 <? php class   Customer   implements   JsonSerializable 
 { 

     private  $name ; 
     private  $email ; 

     public   function  __construct ( $name ,  $email ) 
     { $this -> 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 ); 

Как видите, мы реализуем JsonSerializable , добавив интерфейс в наш класс, а затем добавив метод jsonSerialize в тело нашего класса, чтобы удовлетворить контракт интерфейсов.

В методе jsonSerialize мы создаем и возвращаем массив данных объекта, как мы это делали с другими примерами. Еще раз, если что-то изменится, мы можем просто обновить этот метод. Вы заметите, что метод jsonSerialize просто возвращает массив.

Волшебство приходит, когда вы хотите запустить этот метод, все что нам нужно сделать, это json кодировать экземпляр этого класса, и этот метод будет вызываться автоматически, массив данных возвращается и затем кодируется! Теперь, когда класс реализует интерфейс, мы можем проверить, является ли этот класс экземпляром JsonSerializable . Если вы хотите, вы можете также ввести подсказку в методы, чтобы убедиться, что интерфейс JsonSerializable передан.

Резюме

Благодаря этой простой реализации мы устранили дублирование, сократили объем обслуживания и сократили шансы на появление ошибок. Мы также сделали это простым для другого человека, использующего наш код для проверки способности объекта быть закодированным, проверяя, является ли он экземпляром JsonSerializable .

Приведенные выше примеры, конечно, надуманы, но я надеюсь, что мне удалось продемонстрировать преимущества использования этого интерфейса и вдохновить вас на дальнейшее использование его.