Browse Source

[php] optimize anon objects creation (closes #7916)

Aleksandr Kuzmenko 5 năm trước cách đây
mục cha
commit
1e4ed55dc5

+ 55 - 11
src/generators/genphp7.ml

@@ -540,6 +540,12 @@ let rec write_args (str_writer:string->unit) arg_writer (args:'a list) =
 			str_writer ", ";
 			str_writer ", ";
 			write_args str_writer arg_writer rest
 			write_args str_writer arg_writer rest
 
 
+(**
+	Escapes all "$" chars and encloses `str` into double quotes
+*)
+let quote_string str =
+	"\"" ^ (Str.global_replace (Str.regexp "\\$") "\\$" (String.escaped str)) ^ "\""
+
 (**
 (**
 	Check if specified field is a var with non-constant expression
 	Check if specified field is a var with non-constant expression
 *)
 *)
@@ -1542,12 +1548,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name =
 				| None ->
 				| None ->
 					self#write_expr value_expr;
 					self#write_expr value_expr;
 				| Some key_str ->
 				| Some key_str ->
-					let key_str =
-						Str.global_replace (Str.regexp "\\$")
-						"\\$"
-						(String.escaped key_str)
-					in
-					self#write ("\"" ^ key_str ^ "\" => ");
+					self#write ((quote_string key_str) ^ " => ");
 					self#write_expr value_expr
 					self#write_expr value_expr
 			);
 			);
 			if separate_line then self#write ",\n"
 			if separate_line then self#write ",\n"
@@ -2010,7 +2011,9 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name =
 					match (reveal_expr expr).eexpr with
 					match (reveal_expr expr).eexpr with
 					| TConst TNull -> self#write "'null'"
 					| TConst TNull -> self#write "'null'"
 					| TBinop _ | TUnop _ -> self#write_expr (parenthesis expr)
 					| TBinop _ | TUnop _ -> self#write_expr (parenthesis expr)
-					| TParenthesis { eexpr = (TBinop _ | TUnop _) } -> self#write_expr expr
+					| TParenthesis { eexpr = (TBinop _ | TUnop _) }
+					| TCall ({ eexpr = TField (_, FStatic ({ cl_path = ([],"Std") }, { cf_name = "string" })) }, [_]) ->
+						self#write_expr expr
 					| _ ->
 					| _ ->
 						self#write "(";
 						self#write "(";
 						self#write_expr expr;
 						self#write_expr expr;
@@ -2282,11 +2285,52 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name =
 		*)
 		*)
 		method write_expr_object_declaration fields =
 		method write_expr_object_declaration fields =
 			match fields with
 			match fields with
-				| [] ->  self#write ("new " ^ (self#use hxanon_type_path) ^ "()")
+				| [] -> self#write ("new " ^ (self#use hxanon_type_path) ^ "()")
 				| _ ->
 				| _ ->
-					self#write ("new " ^ (self#use hxanon_type_path)  ^ "(");
-					self#write_assoc_array_decl fields;
-					self#write ")"
+					let consts,args_exprs,args_names,args_fields =
+						List.fold_left (fun (consts,args_exprs,args_names,args_fields) ((name,_,quotes), e) ->
+							match (reveal_expr e).eexpr with
+							| TConst _ ->
+								(name,quotes,e) :: consts, args_exprs, args_names, args_fields
+							| _ ->
+								let arg_name =
+									if quotes = NoQuotes then name
+									else "_hx_" ^ (string_of_int (List.length args_exprs))
+								in
+								consts, e :: args_exprs, arg_name :: args_names, (name, arg_name) :: args_fields
+						) ([],[],[],[]) fields
+					in
+					self#write "new class (";
+					write_args self#write self#write_expr args_exprs;
+					self#write (") extends " ^ (self#use hxanon_type_path) ^ "{\n");
+					self#indent_more;
+					self#write_indentation;
+					self#write "public function __construct(";
+					write_args self#write (fun name -> self#write ("$" ^ name)) args_names;
+					self#write ") {\n";
+					self#indent_more;
+					List.iter (fun (name,quotes,e) ->
+						self#write_indentation;
+						self#write "$this->";
+						if quotes = NoQuotes then self#write name
+						else self#write ("{" ^ (quote_string name) ^ "}");
+						self#write " = ";
+						self#write_expr e;
+						self#write ";\n";
+					) consts;
+					List.iter (fun (name,arg_name) ->
+						self#write_indentation;
+						self#write "$this->";
+						if name = arg_name then self#write name
+						else self#write ("{" ^ (quote_string name) ^ "}");
+						self#write (" = $" ^ arg_name ^ ";\n");
+					) args_fields;
+					self#indent_less;
+					self#write_line "}";
+					self#indent_less;
+					self#write_indentation;
+					self#write "}";
+					(* self#write_assoc_array_decl fields; *)
 		(**
 		(**
 			Writes specified type to output buffer depending on type of expression.
 			Writes specified type to output buffer depending on type of expression.
 		*)
 		*)

+ 4 - 9
std/php/Boot.hx

@@ -557,8 +557,10 @@ class Boot {
 	/**
 	/**
 		Create Haxe-compatible anonymous structure of `data` associative array
 		Create Haxe-compatible anonymous structure of `data` associative array
 	**/
 	**/
-	static public inline function createAnon(data:NativeArray):Dynamic {
-		return new HxAnon(data);
+	static public function createAnon(data:NativeArray):Dynamic {
+		var o = new HxAnon();
+		Syntax.foreach(data, (field:String, value:Any) -> Syntax.setField(o, field, value));
+		return o;
 	}
 	}
 
 
 	/**
 	/**
@@ -940,13 +942,6 @@ private class HxDynamicStr extends HxClosure {
 @:keep
 @:keep
 @:dox(hide)
 @:dox(hide)
 private class HxAnon extends StdClass {
 private class HxAnon extends StdClass {
-	public function new(fields:NativeArray = null) {
-		super();
-		if (fields != null) {
-			Syntax.foreach(fields, function(name, value) Syntax.setField(this, name, value));
-		}
-	}
-
 	@:phpMagic
 	@:phpMagic
 	function __get(name:String) {
 	function __get(name:String) {
 		return null;
 		return null;

+ 1 - 1
std/php/StdClass.hx

@@ -25,5 +25,5 @@ package php;
 @:native('StdClass')
 @:native('StdClass')
 @:phpNoConstructor
 @:phpNoConstructor
 extern class StdClass implements Dynamic {
 extern class StdClass implements Dynamic {
-	function new():Void;
+	@:pure(true) function new():Void;
 }
 }

+ 1 - 1
std/php/_std/Type.hx

@@ -42,7 +42,7 @@ enum ValueType {
 	public static function getClass<T>(o:T):Class<T> {
 	public static function getClass<T>(o:T):Class<T> {
 		if (Global.is_object(o) && !Boot.isClass(o) && !Boot.isEnumValue(o)) {
 		if (Global.is_object(o) && !Boot.isClass(o) && !Boot.isEnumValue(o)) {
 			var cls = Boot.getClass(Global.get_class(cast o));
 			var cls = Boot.getClass(Global.get_class(cast o));
-			return (cls == Boot.getHxAnon() ? null : cast cls);
+			return (Boot.isAnon(o) ? null : cast cls);
 		} else if (Global.is_string(o)) {
 		} else if (Global.is_string(o)) {
 			return cast String;
 			return cast String;
 		} else {
 		} else {