Browse Source

新增 json 转 php 类

朱金辉 2 months ago
parent
commit
b7315308cc
1 changed files with 321 additions and 0 deletions
  1. 321 0
      src/Library/Json2PHP.php

+ 321 - 0
src/Library/Json2PHP.php

@@ -0,0 +1,321 @@
+<?php
+namespace Qii\Library;
+/**
+ * JSON和PHP类互转
+ * @author zjh
+ * 
+ * 使用方法:
+ *
+ * $json2PHP = new \Qii\Library\Json2PHP();
+ * $class = $json2PHP->jsonMarshaller(new \entity\Express\Application(), $jsonStr);
+ * $json2PHP->json2PHP(dirname(__FILE__, 2) . "/entity/Express", 'namespace entity\Express', 'Application', $jsonStr);
+ */
+class Json2PHP {
+    public $useType = false;
+    public function __construct() {
+
+    }
+    /**
+     * JSON decode
+     * @param string $json json数据
+     * @return mixed
+     */
+    public static function decodeJson($json) {
+        return json_decode($json);
+    }
+    /**
+     * JSON 数据绑定 PHP 类属性上
+     * @param object $class 实例化的类
+     * @param object $obj json_decode({})的值,不要要指定第二个参数为true
+     * @return mixed
+     * @throws \Exception
+     */
+    public function jsonMarshaller($class, $json){
+        return $this->jsonBindPHP($class, self::decodeJson($json));
+    }
+
+    /**
+     * JSON 绑定到 PHP 类属性上
+     * @param object $class PHP类
+     * @param object $obj json object
+     * @return mixed
+     * @throws \Exception
+     */
+    protected function jsonBindPHP($class, $obj) {
+        if(gettype($class) != "object") {
+            throw new \Exception('第一个参数必须为类');
+        }
+        $classInfo = $this->classInfo($class);
+        $keys = $classInfo['keys'];
+        if(is_array($obj)){} {
+            foreach ($obj as $key => $value) {
+                $key = ucfirst($key);
+                if(isset($keys[$key])) {
+                    if (in_array($keys[$key]->Type, ['string', 'int', 'boolean'])) {
+                        //echo "1:". $key  .'-> '. $keys[$key]->Type . "\n";
+                        $class->$key = $value;
+                    }else if($this->typeOf($value) == 'array' && in_array($keys[$key]->Type, ['mixed'])){} {
+                        if (in_array($keys[$key]->Type, ['string', 'integer', 'boolean', "double"])) {
+                            //echo "1:". $key  .'-> '. $keys[$key]->Type . "\n";
+                            $class->$key = $value;
+                            continue;
+                        }
+                        $className = $classInfo['namespace'] . '\\' . $key;
+                        //echo "2:". $keys[$key]->Type ."-". $className . '='. $this->typeOf($value) . "\n";
+                        if(class_exists($className, false)) {
+                            if($this->typeOf($value) == 'array') {
+                                foreach ($value as $v) {
+                                    $class->$key[] = $this->jsonBindPHP(new $className(), $v);
+                                }
+                            }else{
+                                $class->$key = $this->jsonBindPHP(new $className(), $value);
+                            }
+
+                        }
+                    }
+                }
+            }
+        }
+        return $class;
+    }
+
+    /**
+     * 获取类所有属性,类属性是public并且大写字母开头同时不能为静态名
+     *
+     * @return array
+     * @throws ReflectionException
+     */
+    public function classInfo($class) {
+        $keys = [];
+        $method = new \ReflectionClass($class);
+        $properties = $method->getproperties();
+        $keys['namespace'] = $method->getNamespaceName();
+        foreach ($properties as $property) {
+            if($property->isPublic() && preg_match("/^[A-Z]+/", $property->getName()) && !$property->isStatic()) {
+                $doc = $property->getDocComment();
+                $keys['keys'][$property->getName()] = (object) ["Type" => $this->getPropertyFromDoc($doc), "Variable" => $this->getTypeFromDoc($doc), "Doc" =>  $doc];
+            }
+        }
+        return $keys;
+    }
+
+    /**
+     * 获取变量类型
+     *
+     * @param string $doc 注释
+     * @return string
+     */
+    public function getTypeFromDoc($doc) {
+        if(preg_match("/[$](.*)=(.*)/", $doc, $match)) {
+            return $match[2];
+        }
+        return '';
+    }
+    /**
+     * 获取变量的类型
+     *
+     * @param string $doc 文档
+     * @return string
+     */
+    public function getPropertyFromDoc($doc) {
+        if(preg_match("/@var\s+(.*)\s+(.*)/U", $doc, $match)) {
+            return $match[1];
+        }
+        return '';
+    }
+
+    /**
+     * JSON 转 PHP 类
+     * @param string $path 保存路径
+     * @param string $namespace 名字空间
+     * @param string $json json 数据
+     * @param $className
+     * @return void
+     */
+    public function json2PHP($path, $namespace, $className, $json) {
+        if($className == '') {
+            $className = "Application";
+        }
+        $className = ucfirst($className);
+        $php = $this->generateJson2PHP($namespace, $className, $json);
+        file_put_contents($path . "/". $className .".php", join("\n", $php));
+    }
+    /**
+     * 生成 json 转 php类
+     *
+     * @param string $namespace 命名空间
+     * @param string $className 类名
+     * @param string $json json数据
+     * @return array
+     * @date
+     */
+    protected function generateJson2PHP($namespace, $className, $json) {
+        $obj = self::decodeJson($json);
+        $line = $this->createClass($className, $obj);
+        $date = date('Y-m-d H:i:s');
+        array_unshift($line,
+            $this->comment([
+                "this file auto create by generateJson2PHP, please do not edit by yourself",
+                "",
+                "@author zjh",
+                "@date {$date}",
+            ]) . "\n"
+        );
+        array_unshift($line, $namespace. ";");
+        array_unshift($line, "<?php");
+        return $line;
+    }
+    /**
+     * @param string $name 类名
+     * @param mixed $values json值
+     * @param bool $isArray false 数组只使用第一个 true 使用所有的
+     * @return array
+     */
+    protected function createClass($name, $values, $isArray = false) {
+        $name = ucfirst($name);
+        $line = [];
+        $line[] = $this->comment([
+            "class {$name}"
+        ], 1);
+        $line[] = "\tclass {$name} {";
+        if($isArray) {
+            $values = $values[0];
+        }
+        if(is_array($values) || is_object($values)) {
+            foreach ($values as $key => $value) {
+                $type = $this->typeOf($value);
+                if($type == 'array' || $type == 'object') {
+                    $isArray = $type == 'array';
+                    $class = $this->createClass($key, $value, $type == 'array');
+                    array_unshift($line, join("\n", $class));
+                    $type = ucfirst($key);
+                    if ($isArray) {
+                        $line[] = $this->comment([
+                                "\${$key} = array",
+                                "@var {$type} \${$key}",
+                                ""
+                            ]
+                            , 2);
+                    }else{
+                        $line[] = $this->comment([
+                                "\${$key} = object",
+                                "@var {$type} \${$key}",
+                                ""
+                            ]
+                            , 2);
+                    }
+                }else{
+                    $line[] = $this->comment([
+                        "@var {$type} \${$key}",
+                        ""
+                    ], 2);
+                }
+                $line[] ="\t\t" .  $this->format('public '. $this->getType($type, $this->useType) .' $'. $key .";");
+            }
+        }else{
+            $type = $this->typeOf($values);
+            $line[] = $this->comment([
+                "@var {$type} \${$values}",
+                ""
+            ], 2);
+            $line[] = "\t\t". $this->format('public '. $this->getType($type, $this->useType) .' $'. $values .";");
+        }
+        $line[] = $this->comment([
+            "魔术方法:使用get变量名获取变量的值"
+        ], 2);
+        $line[] = "\t\tpublic function __call(\$name, \$args){";
+        $line[] = "\t\t\t". 'if(preg_match("/^(get).?/i", $name)){';
+        $line[] = "\t\t\t\t". '$variable = substr($name, 3);';
+        $line[] = "\t\t\t\t". 'if(isset($this->$variable)) {';
+        $line[] = "\t\t\t\t\t". 'return $this->$variable;';
+        $line[] = "\t\t\t\t". '}';
+        $line[] = "\t\t\t}";
+        $line[] = "\t\t\t". 'throw new \Exception("Call to undefined method " . __CLASS__ . "::" . $name . "(". var_export($args, true) .")");';
+        $line[] = "\t\t}";
+
+        $line[] = "\t}\n";
+        return $line;
+    }
+    /**
+     * 去掉两个空格
+     *
+     * @param $str
+     * @return array|string|string[]
+     */
+    public function format($str) {
+        return preg_replace("/\s{2}/", " ", $str);
+    }
+    /**
+     * 注释
+     * @param array $arr 行注释
+     * @param int $space 占几tab个位置
+     * @return string
+     */
+    public function comment($arr, $space = 1) {
+        $line = [];
+        $append = str_pad("", $space, "\t");
+        $line[] = $append . "/**";
+        foreach($arr as $value) {
+            $line[] = $append ." * ". $value;
+        }
+        $line[] = $append . "*/";
+        return join("\n", $line);
+    }
+    /**
+     * 返回值的类型  (boolean, integer, double, float, string, array, object, resource)
+     *
+     * @param $val
+     * @return string
+     */
+    public function typeOf($val) {
+        if(is_bool($val)) {
+            return 'boolean';
+        }
+        if(is_int($val)) {
+            return 'integer';
+        }
+        if(is_double($val)) {
+            return 'double';
+        }
+        if(is_float($val)) {
+            return 'float';
+        }
+        if(is_string($val)) {
+            return 'string';
+        }
+        if(is_array($val)) {
+            return 'array';
+        }
+        if(is_object($val)) {
+            return 'object';
+        }
+        if(is_resource($val)) {
+            return 'resource';
+        }
+        return 'unknown';
+    }
+    /**
+     * 获取强制类型的定义 int, float, bool, string, array, object
+     * @param string $type 类型
+     * @params bool $force 是否强制类型转换
+     * @return string
+     */
+    public function getType($type, $userType = true) {
+        if(!$userType || version_compare(PHP_VERSION, '7.4.0', '<')) {
+            return '';
+        }
+        $type = ["boolean","integer","double","string","array","object","resource"];
+        if(!in_array($type, $allow)) {
+            return '';
+        }
+        switch ($type) {
+            case 'integer':
+                return 'int';
+            case 'double':
+                return 'float';
+            case 'boolean':
+                return 'bool';
+        }
+        return $type;
+    }
+}