|
@@ -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;
|
|
|
+ }
|
|
|
+}
|