Browse Source

[php] Syntax.nativeClassName(); Fixed Type.createInstance() for extern classes (fixes #6848)

Alexander Kuzmenko 7 years ago
parent
commit
a27f9c5a13

+ 17 - 0
src/generators/genphp7.ml

@@ -2381,6 +2381,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 			match name with
 			match name with
 				| "code" | "codeDeref" -> self#write_expr_syntax_code args
 				| "code" | "codeDeref" -> self#write_expr_syntax_code args
 				| "instanceof" -> self#write_expr_syntax_instanceof args
 				| "instanceof" -> self#write_expr_syntax_instanceof args
+				| "nativeClassName" -> self#write_expr_syntax_native_class_name args
 				| "foreach" -> self#write_expr_syntax_foreach args
 				| "foreach" -> self#write_expr_syntax_foreach args
 				| "construct" -> self#write_expr_syntax_construct args
 				| "construct" -> self#write_expr_syntax_construct args
 				| "getField" -> self#write_expr_syntax_get_field args
 				| "getField" -> self#write_expr_syntax_get_field args
@@ -2532,6 +2533,22 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 					);
 					);
 					self#write ")"
 					self#write ")"
 				| _ -> fail self#pos __POS__
 				| _ -> fail self#pos __POS__
+		(**
+			Writes either a "Cls::class" expression (if class is passed directly) or a `$cls->phpClassName` expression
+			(if class is passed as a variable) to output buffer (for `php.Syntax.nativeClassName()`)
+		*)
+		method write_expr_syntax_native_class_name args =
+			match args with
+				| cls_expr :: [] ->
+					(match (reveal_expr cls_expr).eexpr with
+						| TTypeExpr mtype ->
+							self#write (self#use_t (type_of_module_type mtype));
+							self#write "::class"
+						| _ ->
+							self#write_expr cls_expr;
+							self#write "->phpClassName"
+					);
+				| _ -> fail self#pos __POS__
 		(**
 		(**
 			Writes `foreach` expression to output buffer (for `php.Syntax.foreach()`)
 			Writes `foreach` expression to output buffer (for `php.Syntax.foreach()`)
 		*)
 		*)

+ 8 - 0
std/php/Syntax.hx

@@ -165,6 +165,14 @@ extern class Syntax {
     @:overload(function( value:AsVar<Dynamic>, phpClassName:AsVar<String> ) : Bool {})
     @:overload(function( value:AsVar<Dynamic>, phpClassName:AsVar<String> ) : Bool {})
     static function instanceof<V,C>( value:AsVar<V>,  type:AsVar<Class<C>> ) : Bool;
     static function instanceof<V,C>( value:AsVar<V>,  type:AsVar<Class<C>> ) : Bool;
 
 
+    /**
+        Generates PHP class name for a provided Haxe class.
+        ```
+        trace(Syntax.nativeClassName(php.Web)); // outputs: php\Web
+        ```
+     */
+    static function nativeClassName<T>(cls:EitherType<Class<T>, Enum<T>>) : String;
+
     /**
     /**
         ```
         ```
         Syntax.foreach(collection, function(key, value) trace(key, value));
         Syntax.foreach(collection, function(key, value) trace(key, value));

+ 7 - 29
std/php/_std/Type.hx

@@ -107,28 +107,22 @@ enum ValueType {
 	public static function createInstance<T>( cl : Class<T>, args : Array<Dynamic> ) : T {
 	public static function createInstance<T>( cl : Class<T>, args : Array<Dynamic> ) : T {
 		if (String == cast cl) return args[0];
 		if (String == cast cl) return args[0];
 
 
-		var phpName = getPhpName(cl);
-		if (phpName == null) return null;
 		var nativeArgs:NativeArray = @:privateAccess args.arr;
 		var nativeArgs:NativeArray = @:privateAccess args.arr;
-		return Syntax.construct(phpName, Syntax.splat(nativeArgs));
+		return Syntax.construct(Syntax.nativeClassName(cl), Syntax.splat(nativeArgs));
 	}
 	}
 
 
 	public static function createEmptyInstance<T>( cl : Class<T> ) : T {
 	public static function createEmptyInstance<T>( cl : Class<T> ) : T {
 		if (String == cast cl) return cast '';
 		if (String == cast cl) return cast '';
 		if (Array == cast cl) return cast [];
 		if (Array == cast cl) return cast [];
 
 
-		var phpName = getPhpName(cl);
-		if (phpName == null) return null;
-
-		var reflection = new ReflectionClass(phpName);
+		var reflection = new ReflectionClass(Syntax.nativeClassName(cl));
 		return reflection.newInstanceWithoutConstructor();
 		return reflection.newInstanceWithoutConstructor();
 	}
 	}
 
 
 	public static function createEnum<T>( e : Enum<T>, constr : String, ?params : Array<Dynamic> ) : T {
 	public static function createEnum<T>( e : Enum<T>, constr : String, ?params : Array<Dynamic> ) : T {
 		if (e == null || constr == null) return null;
 		if (e == null || constr == null) return null;
 
 
-		var phpName = getPhpName(e);
-		if (phpName == null) return null;
+		var phpName = Syntax.nativeClassName(e);
 
 
 		if (!Global.in_array(constr, Syntax.staticCall(phpName, "__hx__list"))) {
 		if (!Global.in_array(constr, Syntax.staticCall(phpName, "__hx__list"))) {
 			throw 'No such constructor $constr';
 			throw 'No such constructor $constr';
@@ -150,8 +144,7 @@ enum ValueType {
 	public static function createEnumIndex<T>( e : Enum<T>, index : Int, ?params : Array<Dynamic> ) : T {
 	public static function createEnumIndex<T>( e : Enum<T>, index : Int, ?params : Array<Dynamic> ) : T {
 		if (e == null || index == null) return null;
 		if (e == null || index == null) return null;
 
 
-		var phpName = getPhpName(e);
-		if (phpName == null) return null;
+		var phpName = Syntax.nativeClassName(e);
 
 
 		var constructors:NativeIndexedArray<String> = Syntax.staticCall(phpName, "__hx__list");
 		var constructors:NativeIndexedArray<String> = Syntax.staticCall(phpName, "__hx__list");
 		if (index < 0 || index >= Global.count(constructors)) {
 		if (index < 0 || index >= Global.count(constructors)) {
@@ -182,10 +175,7 @@ enum ValueType {
 			];
 			];
 		}
 		}
 
 
-		var phpName = getPhpName(c);
-		if (phpName == null) return null;
-
-		var reflection = new ReflectionClass(phpName);
+		var reflection = new ReflectionClass(Syntax.nativeClassName(c));
 
 
 		var methods = new NativeArray();
 		var methods = new NativeArray();
 		for (m in reflection.getMethods()) {
 		for (m in reflection.getMethods()) {
@@ -219,8 +209,7 @@ enum ValueType {
 		if (c == null) return null;
 		if (c == null) return null;
 		if (c == String) return ['fromCharCode'];
 		if (c == String) return ['fromCharCode'];
 
 
-		var phpName = getPhpName(c);
-		if (phpName == null) return null;
+		var phpName = Syntax.nativeClassName(c);
 
 
 		var reflection = new ReflectionClass(phpName);
 		var reflection = new ReflectionClass(phpName);
 
 
@@ -326,8 +315,7 @@ enum ValueType {
 	public static function allEnums<T>( e : Enum<T> ) : Array<T> {
 	public static function allEnums<T>( e : Enum<T> ) : Array<T> {
 		if (e == null) return null;
 		if (e == null) return null;
 
 
-		var phpName = getPhpName(e);
-		if (phpName == null) return null;
+		var phpName = Syntax.nativeClassName(e);
 
 
 		var result = [];
 		var result = [];
 
 
@@ -341,16 +329,6 @@ enum ValueType {
 		return result;
 		return result;
 	}
 	}
 
 
-	/**
-		Get corresponding PHP name for specified `type`.
-		Returns `null` if `type` does not exist.
-	**/
-	static function getPhpName( type:EitherType<Class<Dynamic>,Enum<Dynamic>> ) : Null<String> {
-		var haxeName = Boot.getHaxeName(cast type);
-
-		return (haxeName == null ? null : Boot.getPhpName(haxeName));
-	}
-
 	/**
 	/**
 		check if specified `name` is a special field name generated by compiler.
 		check if specified `name` is a special field name generated by compiler.
 	 **/
 	 **/

+ 10 - 0
tests/unit/src/unit/TestPhp.hx

@@ -200,6 +200,16 @@ class TestPhp extends Test
 		t(Syntax.instanceof(o, ClosureDummy));
 		t(Syntax.instanceof(o, ClosureDummy));
 		t(Syntax.instanceof(o, phpClassName));
 		t(Syntax.instanceof(o, phpClassName));
 	}
 	}
+
+	@:analyzer(no_user_var_fusion)
+	function testSyntaxNativeClassName() {
+		eq("Array_hx", Syntax.nativeClassName(Array));
+		eq("unit\\Annotation", Syntax.nativeClassName(Annotation));
+		var cls = php.Web;
+		eq("php\\Web", Syntax.nativeClassName(cls));
+		var enm = Annotation;
+		eq("unit\\Annotation", Syntax.nativeClassName(enm));
+	}
 }
 }
 
 
 private class ClosureDummy {
 private class ClosureDummy {

+ 11 - 0
tests/unit/src/unit/issues/Issue6848.hx

@@ -0,0 +1,11 @@
+package unit.issues;
+
+class Issue6848 extends unit.Test {
+#if php
+	function test() {
+		var e = Type.createInstance(php.Exception, ['hello']);
+		t(Std.is(e, php.Exception));
+		eq('hello', e.getMessage());
+	}
+#end
+}