瀏覽代碼

[php7] @:phpNoConstructor for externs which does not have native php ctors and yet can be constructed

Alexander Kuzmenko 8 年之前
父節點
當前提交
48ffece26c
共有 3 個文件被更改,包括 37 次插入5 次删除
  1. 2 0
      src/context/meta.ml
  2. 34 5
      src/generators/genphp7.ml
  3. 1 0
      std/php7/StdClass.hx

+ 2 - 0
src/context/meta.ml

@@ -119,6 +119,7 @@ type strict_meta =
 	| PhpGlobal
 	| PhpClassConst
 	| PhpMagic
+	| PhpNoConstructor
 	| PrivateAccess
 	| Property
 	| Protected
@@ -312,6 +313,7 @@ let get_info = function
 	| PhpGlobal -> ":phpGlobal",("(php7) Puts the static fields of a class in the global PHP namespace",[Platforms [Php;Php];UsedOn TClass])
 	| PhpClassConst -> ":phpClassConst",("(php7)  Generate static var of an extern class as a PHP class constant",[Platform Php;UsedOn TClass])
 	| PhpMagic -> ":phpMagic",("(php7) Treat annotated field as special PHP magic field",[Platform Php;UsedOn TClassField])
+	| PhpNoConstructor -> ":phpNoConstructor",("(php7) Special meta for extern classes which does not have native constructor in PHP, but need a constructor in Haxe extern",[Platform Php;UsedOn TClass])
 	| Public -> ":public",("Marks a class field as being public",[UsedOn TClassField;UsedInternally])
 	| PublicFields -> ":publicFields",("Forces all class fields of inheriting classes to be public",[UsedOn TClass])
 	| QuotedField -> ":quotedField",("Used internally to mark structure fields which are quoted in syntax",[UsedInternally])

+ 34 - 5
src/generators/genphp7.ml

@@ -1268,6 +1268,11 @@ class virtual type_builder ctx wrapper =
 						| ([], "Class") -> "Class"
 						| _ when Meta.has Meta.CoreType abstr.a_meta -> "mixed"
 						| _ -> self#use_t abstr.a_this
+		(**
+			Indicates if there is no constructor in inheritance chain of this type.
+			Own constructor is ignored.
+		*)
+		method private extends_no_constructor = true
 		(**
 			Indicates whether current expression nesting level is a top level of a block
 		*)
@@ -2540,15 +2545,21 @@ class virtual type_builder ctx wrapper =
 			Writes TCall to output buffer
 		*)
 		method private write_expr_call target_expr args =
-			let target_expr = reveal_expr target_expr in
+			let target_expr = reveal_expr target_expr
+			and no_call = ref false in
 			(match target_expr.eexpr with
-				| TConst TSuper -> self#write "parent::__construct"
+				| TConst TSuper ->
+					no_call := self#extends_no_constructor;
+					if not !no_call then self#write "parent::__construct"
 				| TField (expr, FClosure (_,_)) -> self#write_expr (parenthesis target_expr)
 				| _ -> self#write_expr target_expr
 			);
-			self#write "(";
-			write_args buffer self#write_expr args;
-			self#write ")";
+			if not !no_call then
+				begin
+					self#write "(";
+					write_args buffer self#write_expr args;
+					self#write ")"
+				end
 		(**
 			Writes a name of a function or a constant from global php namespace
 		*)
@@ -2857,6 +2868,24 @@ class class_builder ctx (cls:tclass) =
 		*)
 		method is_final_field (field:tclass_field) : bool =
 			Meta.has Meta.Final field.cf_meta
+		(**
+			Check if there is no native php constructor in inheritance chain of this class.
+			E.g. `StsClass` does have a constructor while still can be called with `new StdClass()`.
+			So this method will return true for `MyClass` if `MyClass extends StdClass`.
+		*)
+		method private extends_no_constructor =
+			let rec extends_no_constructor tcls =
+				match tcls.cl_super with
+					| None -> true
+					| Some (parent, _) ->
+						if Meta.has Meta.PhpNoConstructor parent.cl_meta then
+							true
+						else
+							match parent.cl_constructor with
+								| Some _ -> false
+								| None -> extends_no_constructor parent
+			in
+			extends_no_constructor cls
 		(**
 			Recursively check if current class is a parent class for a `child`
 		*)

+ 1 - 0
std/php7/StdClass.hx

@@ -1,6 +1,7 @@
 package php;
 
 @:native('StdClass')
+@:phpNoConstructor
 extern class StdClass implements Dynamic {
 	function new() : Void;
 }