জেএসএনে পিএইচপি অবজেক্টটি সিরিয়াল করা হচ্ছে


101

তাই আমি ঘুরে বেড়ানো ছিল php.net serializing পিএইচপি তাদেরকে JSON করার বস্তু, যখন আমি নতুন জুড়ে পদস্খলিত সম্পর্কে তথ্যের জন্য JsonSerializable ইন্টারফেস । এটি কেবলমাত্র পিএইচপি> = 5.4 , এবং আমি 5.3.x পরিবেশে চলেছি।

এই ধরণের কার্যকারিতা কীভাবে পিএইচপি <5.4 অর্জন করেছে ?

আমি এখনও জেএসএনের সাথে খুব বেশি কাজ করি নি, তবে আমি একটি অ্যাপ্লিকেশনটিতে একটি এপিআই লেয়ার সমর্থন করার চেষ্টা করছি এবং ডেটা অবজেক্টটি ( যা অন্যথায় দর্শনে প্রেরণ করা হবে) জেএসএনে ডাম্প করা সঠিক হবে।

আমি যদি সরাসরি অবজেক্টটি সিরিয়ালাইজ করার চেষ্টা করি তবে এটি একটি খালি JSON স্ট্রিং দেয়; যার কারণ আমি ধরে নিয়েছি json_encode()হ্যাক অবজেক্টটির সাথে কী করবে তা আমি জানি না। আমি যাও recursively একটি অ্যারের মধ্যে বস্তুর হ্রাস করা উচিত, এবং তারপর এনকোড যে ?


উদাহরণ

$data = new Mf_Data();
$data->foo->bar['hello'] = 'world';

echo json_encode($data) একটি খালি বস্তু উত্পাদন করে:

{}

var_dump($data) তবে প্রত্যাশার মতো কাজ করে:

object(Mf_Data)#1 (5) {
  ["_values":"Mf_Data":private]=>
  array(0) {
  }
  ["_children":"Mf_Data":private]=>
  array(1) {
    [0]=>
    array(1) {
      ["foo"]=>
      object(Mf_Data)#2 (5) {
        ["_values":"Mf_Data":private]=>
        array(0) {
        }
        ["_children":"Mf_Data":private]=>
        array(1) {
          [0]=>
          array(1) {
            ["bar"]=>
            object(Mf_Data)#3 (5) {
              ["_values":"Mf_Data":private]=>
              array(1) {
                [0]=>
                array(1) {
                  ["hello"]=>
                  string(5) "world"
                }
              }
              ["_children":"Mf_Data":private]=>
              array(0) {
              }
              ["_parent":"Mf_Data":private]=>
              *RECURSION*
              ["_key":"Mf_Data":private]=>
              string(3) "bar"
              ["_index":"Mf_Data":private]=>
              int(0)
            }
          }
        }
        ["_parent":"Mf_Data":private]=>
        *RECURSION*
        ["_key":"Mf_Data":private]=>
        string(3) "foo"
        ["_index":"Mf_Data":private]=>
        int(0)
      }
    }
  }
  ["_parent":"Mf_Data":private]=>
  NULL
  ["_key":"Mf_Data":private]=>
  NULL
  ["_index":"Mf_Data":private]=>
  int(0)
}

অভিযোজ্য বস্তু

1)

সুতরাং এই toArray()ফাংশনটি আমি Mf_Dataক্লাসের জন্য তৈরি করেছি :

public function toArray()
{
    $array = (array) $this;
    array_walk_recursive($array, function (&$property) {
        if ($property instanceof Mf_Data) {
            $property = $property->toArray();
        }
    });
    return $array;
}

তবে যেহেতু Mf_Dataঅবজেক্টগুলিরও তাদের পিতামাতাকে ধারণ করে ( ধারণ করে ) অবজেক্ট রয়েছে তাই এটি পুনরাবৃত্তি করে ব্যর্থ হয়। আমি যখন _parentরেফারেন্সটি সরিয়ে থাকি তখন কবজির মতো কাজ করে ।

2)

কেবল অনুসরণ করার জন্য, আমি যে জটিল ট্রি-নোড অবজেক্টটি দিয়েছিলাম তার রূপান্তর করার চূড়ান্ত কাজটি ছিল:

// class name - Mf_Data
// exlcuded properties - $_parent, $_index
public function toArray()
{
    $array = get_object_vars($this);
    unset($array['_parent'], $array['_index']);
    array_walk_recursive($array, function (&$property) {
        if (is_object($property) && method_exists($property, 'toArray')) {
            $property = $property->toArray();
        }
    });
    return $array;
}

3)

আমি আবার প্রয়োগ করছি, একটি বাস্তবায়ন কিছুটা ক্লিনার দিয়ে। একটি instanceofচেকের জন্য ইন্টারফেস ব্যবহার করা তুলনায় অনেক পরিষ্কার মনে হয় method_exists()( তবে method_exists()ক্রস-কাট উত্তরাধিকার / বাস্তবায়ন হয় )।

ব্যবহারটিও unset()কিছুটা অগোছালো মনে হয়েছিল এবং মনে হচ্ছে যুক্তিটি অন্য কোনও পদ্ধতিতে রিফ্যাক্ট করা উচিত। যাইহোক, এই বাস্তবায়ন করে সম্পত্তি অ্যারে (কপি কারণেarray_diff_key ,) অতএব আপনি ভেবে দেখুন কিছু।

interface ToMapInterface
{

    function toMap();

    function getToMapProperties();

}

class Node implements ToMapInterface
{

    private $index;
    private $parent;
    private $values = array();

    public function toMap()
    {
        $array = $this->getToMapProperties();
        array_walk_recursive($array, function (&$value) {
            if ($value instanceof ToMapInterface) {
                $value = $value->toMap();
            }
        });
        return $array;
    }

    public function getToMapProperties()
    {
        return array_diff_key(get_object_vars($this), array_flip(array(
            'index', 'parent'
        )));
    }

}

4
+1 দুর্দান্ত প্রশ্ন, এই বৈশিষ্ট্যটি এখনও জানতেন না।
তাকেশিন

@ টাকেশিন - ইয়ুপ, ডক পৃষ্ঠায় সম্পাদনার তারিখ 4 দিন আগে। আমি এটা দেখে খুশি!
ড্যান লগ

2
এটি দেখার অন্যদের রেফারেন্সের জন্য, json_encode অবজেক্টগুলিকে ঠিকঠাকভাবে পরিচালনা করতে পারে। তবে এটি কেবলমাত্র সেই অবজেক্টের সর্বজনীন সদস্যকে এনকোড করে। সুতরাং আপনি যদি সুরক্ষিত বা প্রাইভেট ক্লাসের ভেরিয়েবলগুলি রাখেন তবে আপনার পোস্ট পদ্ধতিগুলির মধ্যে একটির প্রয়োজন হয়, বা জসনসারিয়ালযোগ্য।
ম্যাথু হার্বস্ট

নিবন্ধন করুন পুরানো প্রশ্ন এখন পুরানো, এবং <5.4 আসলে আর কোনও বিকল্প নয় (বা কমপক্ষে হওয়া উচিত নয়) অবশ্যইJsonSerializable
ড্যান লাগ

উত্তর:


45

সম্পাদনা করুন : এটি বর্তমানে 2016-09-24, এবং পিএইচপি 5.4 প্রকাশিত হয়েছে 2012-03-01, এবং সমর্থনটি 2015-09-01 এ শেষ হয়েছে । তবুও, এই উত্তরটি upvotes লাভ বলে মনে হচ্ছে। আপনি যদি এখনও পিএইচপি <5.4 ব্যবহার করেন তবে আপনি একটি সুরক্ষা ঝুঁকি তৈরি করছেন এবং আপনার প্রকল্পকে দীর্ঘস্থায়ী করছেন । যদি আপনার কাছে <5.4 এ থাকার বা যদি ইতিমধ্যে সংস্করণ> = 5.4 ব্যবহার করার কোনও বাধ্যতামূলক কারণ না থাকে তবে এই উত্তরটি ব্যবহার করবেন না এবং কেবল পিএইচপি> = 5.4 ব্যবহার করুন (বা আপনি জানেন যে সাম্প্রতিক একটি) এবং জসনসিরাইজিয়েবল ইন্টারফেস প্রয়োগ করুন


আপনি উদাহরণস্বরূপ একটি ফাংশন সংজ্ঞায়িত করবেন getJsonData();, যা কোনও অ্যারে, stdClassঅবজেক্ট বা দৃশ্যমান পরামিতিগুলির পরিবর্তে প্রাইভেট / সুরক্ষিত উপাদানগুলির সাথে ফিরে আসবে এবং একটি করবে json_encode($data->getJsonData());। সংক্ষেপে, 5.4 থেকে ফাংশনটি বাস্তবায়ন করুন, তবে এটিকে হাতে কল করুন।

get_object_vars()শ্রেণীর অভ্যন্তরীণ থেকে প্রাইভেট / সুরক্ষিত ভেরিয়েবলের অ্যাক্সেসের মতো এ জাতীয় কিছু কাজ করবে :

function getJsonData(){
    $var = get_object_vars($this);
    foreach ($var as &$value) {
        if (is_object($value) && method_exists($value,'getJsonData')) {
            $value = $value->getJsonData();
        }
    }
    return $var;
}

2
ধন্যবাদ @ ব্রিকেন - কোনও কোনও এসোসিয়েটিভ অ্যারেতে কোনও বস্তু (এতে দৃশ্যমানতা বা প্রকার নির্বিশেষে সমস্ত সদস্য ) হ্রাস করার জন্য কী কোনও শর্টকাট আছে , বা এটিকে টাইপকেস্ট করার জন্য stdClass? আমি প্রতিবিম্বের দিক দিয়ে ভাবছি , তবে তা না হলে আমি এটি পুনরুক্তি সম্পাদন করার জন্য কিছু খুঁজে বের করব।
ড্যান লগ

প্রতিবিম্ব দীর্ঘ পথ হবে। আপনি যেমন নিজের ফাংশনে ক্লাসের ভিতরেgetJsonData() রয়েছেন, আপনি কেবল কল করতে পারেন get_object_vars()এবং আরও ফলাফলের সন্ধানের ফলে লুপ করতে পারেন ।
রিক্কেন

আমি এটি প্রায় বাছাই করেছি; বিষয়টি এখন পুনরাবৃত্তি। প্রতিটি বস্তুর একটি _parentসম্পত্তি থাকে যাতে গাছটি রুটে যেতে পারে। একটি আপডেটের জন্য আমার সম্পাদনা দেখুন; সম্ভবত আমার আর একটি প্রশ্ন জিজ্ঞাসা করা উচিত কারণ এই সমস্যাটি এখন আমার আসল থেকে বাদ দেওয়া হয়েছে।
ড্যান লগ

unset($array['_parent']);হাঁটার আগে একটি সহজ কৌশলটি করা উচিত।
Wrkken

আশ্চর্যজনক, ধন্যবাদ @ ব্রিকেন - আমি জটিল সমতা পরীক্ষার চেষ্টা করতে শুরু করেছিলাম, একটি প্রসঙ্গ অবজেক্টটিকে $parentব্যবহারকারী-ডেটা হিসাবে পাস করছিলাম array_walk_recursive()। সরল সুন্দর! এছাড়াও, এটি $array["\0class\0property"]নাল-বাইট দূষণের কারণে কারণ আমি ingালাই ব্যবহার করছি। আমি মনে করি আমি স্যুইচ করব get_object_vars()
ড্যান লগ

91

সবচেয়ে সহজ ক্ষেত্রে টাইপ ইঙ্গিত কাজ করা উচিত:

$json = json_encode( (array)$object );

7
আপনি যদি নেমস্পেস এবং অটো লোডার দিয়ে কাজ করেন তবে এটি দীর্ঘ বাতাসযুক্ত / কুৎসিত সম্পত্তি নাম দেয়।
বিটা রাইড

এটিই সেরা সমাধান, সুনির্দিষ্ট এবং সংক্ষিপ্ত!
সুজল মন্ডল

4
ক্লিনার সম্পত্তির নাম পাওয়ার কোনও উপায় আছে?
ক্রিস্টোফার

5
প্রপ নামগুলির শুরুতে এটি কেন \ u0000 * \ u0000 যুক্ত করে?
এলিয়া ওয়েইস

1
ব্যক্তিগত সম্পত্তি সহ অকেজো। আপনার সকলকে এন.ইউইকিপিডিয়া . org / উইকি / ওপেন / ক্লোজড_নীতি সম্পর্কে শিখতে হবে ।
ফ্যাবিয়ান পিকন

19

json_encode()শুধুমাত্র পাবলিক সদস্য ভেরিয়েবলগুলি এনকোড করবে। সুতরাং আপনি যদি ব্যক্তিগতটি একবার যুক্ত করতে চান তবে নিজের দ্বারা এটি করতে হবে (অন্যরা যেমন পরামর্শ দিয়েছে)


8

নিম্নলিখিত কোডটি প্রতিবিম্ব ব্যবহার করে কাজ করছে। এটি ধরে নিয়েছে যে আপনি যে বৈশিষ্ট্যগুলি সিরিয়ালায়িত করতে চান তার জন্য আপনার কাছে গ্রাহক রয়েছে

    <?php

    /**
     * Serialize a simple PHP object into json
     * Should be used for POPO that has getter methods for the relevant properties to serialize
     * A property can be simple or by itself another POPO object
     *
     * Class CleanJsonSerializer
     */
    class CleanJsonSerializer {

    /**
     * Local cache of a property getters per class - optimize reflection code if the same object appears several times
     * @var array
     */
    private $classPropertyGetters = array();

    /**
     * @param mixed $object
     * @return string|false
     */
    public function serialize($object)
    {
        return json_encode($this->serializeInternal($object));
    }

    /**
     * @param $object
     * @return array
     */
    private function serializeInternal($object)
    {
        if (is_array($object)) {
            $result = $this->serializeArray($object);
        } elseif (is_object($object)) {
            $result = $this->serializeObject($object);
        } else {
            $result = $object;
        }
        return $result;
    }

    /**
     * @param $object
     * @return \ReflectionClass
     */
    private function getClassPropertyGetters($object)
    {
        $className = get_class($object);
        if (!isset($this->classPropertyGetters[$className])) {
            $reflector = new \ReflectionClass($className);
            $properties = $reflector->getProperties();
            $getters = array();
            foreach ($properties as $property)
            {
                $name = $property->getName();
                $getter = "get" . ucfirst($name);
                try {
                    $reflector->getMethod($getter);
                    $getters[$name] = $getter;
                } catch (\Exception $e) {
                    // if no getter for a specific property - ignore it
                }
            }
            $this->classPropertyGetters[$className] = $getters;
        }
        return $this->classPropertyGetters[$className];
    }

    /**
     * @param $object
     * @return array
     */
    private function serializeObject($object) {
        $properties = $this->getClassPropertyGetters($object);
        $data = array();
        foreach ($properties as $name => $property)
        {
            $data[$name] = $this->serializeInternal($object->$property());
        }
        return $data;
    }

    /**
     * @param $array
     * @return array
     */
    private function serializeArray($array)
    {
        $result = array();
        foreach ($array as $key => $value) {
            $result[$key] = $this->serializeInternal($value);
        }
        return $result;
    }  
} 

1
আমি এখনই তোমার প্রেমে পড়েছি! আমি আপনাকে কিছু বেকন বা বিয়ার বা একটি কাপকেক প্রেরণ করব কাপ কাপের কী?
জোনাথন ডস সান্টোস 21

এটি একটি দুর্দান্ত ক্লাস! এটি সুরক্ষিত অবজেক্ট আইটেমগুলির সাথেও কাজ করে।
রোলফ বার্কেপেইস


2

যেহেতু আপনার অবজেক্টের ধরণটি প্রথাগত, তাই আমি আপনার সমাধানের সাথে একমত হতে চাই - এটি একটি এনকোডিং পদ্ধতি (জেএসএন বা বিষয়বস্তু সিরিয়ালকরণের মতো) ব্যবহার করে ছোট ভাগে বিভক্ত করুন এবং অন্য প্রান্তে অবজেক্টটি পুনর্নির্মাণের জন্য সংশ্লিষ্ট কোড রয়েছে।


2

আমার সংস্করণ:

json_encode(self::toArray($ob))

বাস্তবায়ন:

private static function toArray($object) {
    $reflectionClass = new \ReflectionClass($object);

    $properties = $reflectionClass->getProperties();

    $array = [];
    foreach ($properties as $property) {
        $property->setAccessible(true);
        $value = $property->getValue($object);
        if (is_object($value)) {
            $array[$property->getName()] = self::toArray($value);
        } else {
            $array[$property->getName()] = $value;
        }
    }
    return $array;
}

জসন ইউটিলস: গিটহাব


ঠিক আমি খুঁজছেন ছিল কি। প্রাইভেটের সাথে সমস্যা সমাধান করে। সহজ এবং ছোট।
ফ্যাবিয়ান পিকন

1

এটি ব্যবহার করার চেষ্টা করুন, এটি আমার পক্ষে ভাল কাজ করেছে।

json_encode(unserialize(serialize($array)));

1

আপনার পরিবর্তনশীল প্রকারে পরিবর্তন privateকরুনpublic

এটি সহজ এবং আরও পঠনযোগ্য।

উদাহরণ স্বরূপ

কাজ করছে না;

class A{
   private $var1="valuevar1";
   private $var2="valuevar2";
   public function tojson(){
    return json_encode($this)
   }
}

এটি কাজ করছে;

class A{
   public $var1="valuevar1";
   public $var2="valuevar2";
   public function tojson(){
    return json_encode($this)
   }
}

এটি খুব বিজোড় কিন্তু এটা সত্য.
অ্যাবিলোগোস

0

আমি একটি দুর্দান্ত সহায়ক শ্রেণি তৈরি করেছি যা কোনও পদার্থকে অ্যারেতে রূপান্তরিত করে object এটি বৈশিষ্ট্যগুলির উপর নির্ভর করে না, কেবল পদ্ধতিগুলি।

সুতরাং আমার কাছে একটি নীচের পর্যালোচনা অবজেক্ট রয়েছে যার মধ্যে দুটি পদ্ধতি রয়েছে:

পুনঃমূল্যায়ন

  • getAmountReviews: int
  • getReviews: মন্তব্যের অ্যারে

মন্তব্য

  • getSubject
  • getDescription

আমি যে স্ক্রিপ্টটি লিখেছি তা এটিকে বৈশিষ্ট্যযুক্ত এমন একটি অ্যারেতে রূপান্তরিত করবে:

    {
      amount_reviews: 21,
      reviews: [
        {
          subject: "In een woord top 1!",
          description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque laoreet lacus quis eros venenatis, sed tincidunt mi rhoncus. Aliquam ut pharetra diam, nec lobortis dolor."
        },
        {
          subject: "En een zwembad 2!",
          description: "Maecenas et aliquet mi, a interdum mauris. Donec in egestas sem. Sed feugiat commodo maximus. Pellentesque porta consectetur commodo. Duis at finibus urna."
        },
        {
          subject: "In een woord top 3!",
          description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque laoreet lacus quis eros venenatis, sed tincidunt mi rhoncus. Aliquam ut pharetra diam, nec lobortis dolor."
        },
        {
          subject: "En een zwembad 4!",
          description: "Maecenas et aliquet mi, a interdum mauris. Donec in egestas sem. Sed feugiat commodo maximus. Pellentesque porta consectetur commodo. Duis at finibus urna."
       },
       {
          subject: "In een woord top 5!",
          description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque laoreet lacus quis eros venenatis, sed tincidunt mi rhoncus. Aliquam ut pharetra diam, nec lobortis dolor."
    }
]}

উত্স: পিএইচপি সিরিয়ালাইজার যা কোনও বস্তুকে একটি অ্যারেতে রূপান্তর করে যা JSON এ এনকোড করা যেতে পারে।

আপনাকে যা করতে হবে তা হ'ল আউটপুটটির চারপাশে জসন_নকোড মোড়ানো।

লিপি সম্পর্কে কিছু তথ্য:

  • Get এর সাথে শুরু হওয়া পদ্ধতিগুলি কেবল যুক্ত করা হয়
  • ব্যক্তিগত পদ্ধতি উপেক্ষা করা হয়
  • নির্মাণকারী উপেক্ষা করা হয়
  • পদ্ধতির নামের মূল অক্ষরগুলি একটি আন্ডারস্কোর এবং লোয়ারকেসড অক্ষর দ্বারা প্রতিস্থাপন করা হবে

-7

আমি একই সমস্যা কয়েক ঘন্টা ব্যয়। কনভার্ট করার আমার অবজেক্টে আরও অনেকগুলি রয়েছে যার সংজ্ঞাগুলি আমার (এপিআই) স্পর্শ করার কথা নয়, তাই আমি এমন একটি সমাধান নিয়ে এসেছি যা অনুমান করা ধীর হতে পারে তবে আমি এটিকে বিকাশের উদ্দেশ্যে ব্যবহার করছি।

এটি একটিতে কোনও বস্তুকে অ্যারে রূপান্তর করে

function objToArr($o) {
$s = '<?php
class base {
    public static function __set_state($array) {
        return $array;
    }
}
function __autoload($class) {
    eval("class $class extends base {}");
}
$a = '.var_export($o,true).';
var_export($a);
';
$f = './tmp_'.uniqid().'.php';
file_put_contents($f,$s);
chmod($f,0755);
$r = eval('return '.shell_exec('php -f '.$f).';');
unlink($f);
return $r;
}

এটি যে কোনও বস্তুকে stdClass এ রূপান্তর করে

class base {
    public static function __set_state($array) {
        return (object)$array;
    }
}
function objToStd($o) {
$s = '<?php
class base {
    public static function __set_state($array) {
        $o = new self;
        foreach($array as $k => $v) $o->$k = $v;
        return $o;
    }
}
function __autoload($class) {
    eval("class $class extends base {}");
}
$a = '.var_export($o,true).';
var_export($a);
';
$f = './tmp_'.uniqid().'.php';
file_put_contents($f,$s);
chmod($f,0755);
$r = eval('return '.shell_exec('php -f '.$f).';');
unlink($f);
return $r;
}

ইতিমধ্যে স্বীকৃত অন্য একটি সূক্ষ্ম এবং নির্ভুল উত্তর রয়েছে। আপনার উত্তর কি আমূল কিছু আলাদা, আরও দক্ষ বা কমপ্যাক্ট যুক্ত করে? আমি অনুমান করি না
ইয়ারোস্লাভ

আমি সৎ হতে চলেছি; আমি মনে করি না এটি এই প্রশ্নের উত্তর দেয় না।
ড্যান লগ

5
প্রায় 6 মাস কেটে গেছে; আমি পর্যায়ক্রমে এখানে ফিরে এসেছি এবং ভবিষ্যতের দর্শকদের জন্য কিছু সম্পাদনা করতে; এই কাজটি করার কী আছে তা আমার এখনও ধারণা নেই।
ড্যান লাগেজ

unlink($thisAnswer);
ড্যান লগ

লোকেরা যা বোঝে না সেগুলি হ্রাস করে। এটি সঠিক সমাধান বলার অপেক্ষা রাখে না তবে এটি সন্ধান করার মতো কিছু। সেক্ষেত্রে আপনি ডাউনভোটদের আগে স্পষ্টতা চাইবেন।
গিমালী
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.