123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917 |
- /*
- * Copyright (C)2005-2017 Haxe Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
- package php;
- import haxe.PosInfos;
- using php.Global;
- /**
- Various Haxe->PHP compatibility utilities.
- You should not use this class directly.
- **/
- @:keep
- @:dox(hide)
- class Boot {
- /** List of Haxe classes registered by their PHP class names */
- @:protected static var aliases = new NativeAssocArray<String>();
- /** Cache of HxClass instances */
- @:protected static var classes = new NativeAssocArray<HxClass>();
- /** List of getters (for Reflect) */
- @:protected static var getters = new NativeAssocArray<NativeAssocArray<Bool>>();
- /** List of setters (for Reflect) */
- @:protected static var setters = new NativeAssocArray<NativeAssocArray<Bool>>();
- /** Metadata storage */
- @:protected static var meta = new NativeAssocArray<{}>();
- /**
- Initialization stuff.
- This method is called once before invoking any Haxe-generated user code.
- **/
- static function __init__() {
- if (!Global.defined('HAXE_CUSTOM_ERROR_HANDLER') || !Const.HAXE_CUSTOM_ERROR_HANDLER) {
- var previousLevel = Global.error_reporting(Const.E_ALL);
- var previousHandler = Global.set_error_handler(
- function (errno:Int, errstr:String, errfile:String, errline:Int) {
- if (Global.error_reporting() & errno == 0) {
- return false;
- }
- throw new ErrorException(errstr, 0, errno, errfile, errline);
- }
- );
- //Already had user-defined handler. Return it.
- if (previousHandler != null) {
- Global.error_reporting(previousLevel);
- Global.set_error_handler(previousHandler);
- }
- }
- }
- /**
- Returns root namespace based on a value of `--php-prefix` compiler flag.
- Returns empty string if no `--php-prefix` provided.
- **/
- public static inline function getPrefix() : String {
- return untyped __php__('self::PHP_PREFIX');
- }
- /**
- Register list of getters to be able to call getters using reflection
- **/
- public static function registerGetters( phpClassName:String, list:NativeAssocArray<Bool> ) : Void {
- getters[phpClassName] = list;
- }
- /**
- Register list of setters to be able to call getters using reflection
- **/
- public static function registerSetters( phpClassName:String, list:NativeAssocArray<Bool> ) : Void {
- setters[phpClassName] = list;
- }
- /**
- Check if specified property has getter
- **/
- public static function hasGetter( phpClassName:String, property:String ) : Bool {
- ensureLoaded(phpClassName);
- var has = false;
- var phpClassName:haxe.extern.EitherType<Bool,String> = phpClassName;
- do {
- has = Global.isset(getters[phpClassName][property]);
- phpClassName = Global.get_parent_class(phpClassName);
- } while (!has && phpClassName != false && Global.class_exists(phpClassName));
- return has;
- }
- /**
- Check if specified property has setter
- **/
- public static function hasSetter( phpClassName:String, property:String ) : Bool {
- ensureLoaded(phpClassName);
- var has = false;
- var phpClassName:haxe.extern.EitherType<Bool,String> = phpClassName;
- do {
- has = Global.isset(setters[phpClassName][property]);
- phpClassName = Global.get_parent_class(phpClassName);
- } while (!has && phpClassName != false && Global.class_exists(phpClassName));
- return has;
- }
- /**
- Save metadata for specified class
- **/
- public static function registerMeta( phpClassName:String, data:Dynamic ) : Void {
- meta[phpClassName] = data;
- }
- /**
- Retrieve metadata for specified class
- **/
- public static function getMeta( phpClassName:String ) : Null<Dynamic> {
- ensureLoaded(phpClassName);
- return Global.isset(meta[phpClassName]) ? meta[phpClassName] : null;
- }
- /**
- Associate PHP class name with Haxe class name
- **/
- public static function registerClass( phpClassName:String, haxeClassName:String ) : Void {
- aliases[phpClassName] = haxeClassName;
- }
- /**
- Returns a list of currently loaded haxe-generated classes.
- **/
- public static function getRegisteredClasses():Array<Class<Dynamic>> {
- var result = [];
- Syntax.foreach(aliases, function(phpName, haxeName) {
- result.push(cast getClass(phpName));
- });
- return result;
- }
- /**
- Returns a list of phpName=>haxeName for currently loaded haxe-generated classes.
- **/
- public static function getRegisteredAliases():NativeAssocArray<String> {
- return aliases;
- }
- /**
- Get Class<T> instance for PHP fully qualified class name (E.g. '\some\pack\MyClass')
- It's always the same instance for the same `phpClassName`
- **/
- public static function getClass( phpClassName:String ) : HxClass {
- if (phpClassName.charAt(0) == '\\') {
- phpClassName = phpClassName.substr(1);
- }
- if (!Global.isset(classes[phpClassName])) {
- classes[phpClassName] = new HxClass(phpClassName);
- }
- return classes[phpClassName];
- }
- /**
- Returns Class<HxAnon>
- **/
- public static inline function getHxAnon() : HxClass {
- return cast HxAnon;
- }
- /**
- Returns Class<HxClass>
- **/
- public static inline function getHxClass() : HxClass {
- return cast HxClass;
- }
- /**
- Returns either Haxe class name for specified `phpClassName` or (if no such Haxe class registered) `phpClassName`.
- **/
- public static function getClassName( phpClassName:String ) : String {
- var hxClass = getClass(phpClassName);
- var name = getHaxeName(hxClass);
- return (name == null ? hxClass.phpClassName : name);
- }
- /**
- Returns original Haxe fully qualified class name for this type (if exists)
- **/
- public static function getHaxeName( hxClass:HxClass) : Null<String> {
- switch (hxClass.phpClassName) {
- case 'Int': return 'Int';
- case 'String': return 'String';
- case 'Bool': return 'Bool';
- case 'Float': return 'Float';
- case 'Class': return 'Class';
- case 'Enum': return 'Enum';
- case 'Dynamic': return 'Dynamic';
- case _:
- }
- inline function exists() return Global.isset(aliases[hxClass.phpClassName]);
- if (exists()) {
- return aliases[hxClass.phpClassName];
- } else if (Global.class_exists(hxClass.phpClassName) && exists()) {
- return aliases[hxClass.phpClassName];
- } else if (Global.interface_exists(hxClass.phpClassName) && exists()) {
- return aliases[hxClass.phpClassName];
- }
- return null;
- }
- /**
- Find corresponding PHP class name.
- Returns `null` if specified class does not exist.
- **/
- public static function getPhpName( haxeName:String ) : Null<String> {
- var prefix = getPrefix();
- var phpParts = (prefix.length == 0 ? [] : [prefix]);
- var haxeParts = haxeName.split('.');
- for (part in haxeParts) {
- switch (part.toLowerCase()) {
- case "__halt_compiler" | "abstract" | "and" | "array" | "as" | "break" | "callable" | "case" | "catch" | "class"
- | "clone" | "const" | "continue" | "declare" | "default" | "die" | "do" | "echo" | "else" | "elseif" | "empty"
- | "enddeclare" | "endfor" | "endforeach" | "endif" | "endswitch" | "endwhile" | "eval" | "exit" | "extends"
- | "final" | "finally" | "for" | "foreach" | "function" | "global" | "goto" | "if" | "implements" | "include"
- | "include_once" | "instanceof" | "insteadof" | "interface" | "isset" | "list" | "namespace" | "new" | "or"
- | "print" | "private" | "protected" | "public" | "require" | "require_once" | "return" | "static" | "switch"
- | "throw" | "trait" | "try" | "unset" | "use" | "var" | "while" | "xor" | "yield" | "__class__" | "__dir__"
- | "__file__" | "__function__" | "__line__" | "__method__" | "__trait__" | "__namespace__" | "int" | "float"
- | "bool" | "string" | "true" | "false" | "null" | "parent" | "void" | "iterable":
- part += '_hx';
- case _:
- }
- phpParts.push(part);
- }
- return phpParts.join('\\');
- }
- /**
- Creates Haxe-compatible closure.
- @param type `this` for instance methods; full php class name for static methods
- @param func Method name
- **/
- public static inline function closure( target:Dynamic, func:Dynamic ) : HxClosure {
- return new HxClosure(target, func);
- }
- /**
- Unsafe cast to HxClosure
- **/
- public static inline function castClosure(value:Dynamic) : HxClosure {
- return value;
- }
- /**
- Unsafe cast to HxClass
- **/
- public static inline function castClass(cls:Class<Dynamic>) : HxClass {
- return cast cls;
- }
- /**
- Returns `Class<T>` for `HxClosure`
- **/
- public static inline function closureHxClass() : HxClass {
- return cast HxClosure;
- }
- /**
- Implementation for `cast(value, Class<Dynamic>)`
- @throws HxException if `value` cannot be casted to this type
- **/
- public static function typedCast( hxClass:HxClass, value:Dynamic ) : Dynamic {
- switch (hxClass.phpClassName) {
- case 'Int':
- if (Boot.isNumber(value)) {
- return Global.intval(value);
- }
- case 'Float':
- if (Boot.isNumber(value)) {
- return value.floatval();
- }
- case 'Bool':
- if (value.is_bool()) {
- return value;
- }
- case 'String':
- if (value.is_string()) {
- return value;
- }
- case 'php\\NativeArray':
- if (value.is_array()) {
- return value;
- }
- case _:
- if (value.is_object() && Std.is(value, cast hxClass)) {
- return value;
- }
- }
- throw 'Cannot cast ' + Std.string(value) + ' to ' + getClassName(hxClass.phpClassName);
- }
- /**
- `trace()` implementation
- **/
- public static function trace( value:Dynamic, infos:PosInfos ) : Void {
- if (infos != null) {
- Global.echo('${infos.fileName}:${infos.lineNumber}: ');
- }
- Global.echo(stringify(value));
- if (infos.customParams != null) {
- for (value in infos.customParams) {
- Global.echo(',' + stringify(value));
- }
- }
- Global.echo('\n');
- }
- /**
- Returns string representation of `value`
- **/
- public static function stringify( value : Dynamic ) : String {
- if (value == null) {
- return 'null';
- }
- if (value.is_string()) {
- return value;
- }
- if (value.is_int() || value.is_float()) {
- return Syntax.string(value);
- }
- if (value.is_bool()) {
- return value ? 'true' : 'false';
- }
- if (value.is_array()) {
- var strings = Syntax.arrayDecl();
- Syntax.foreach(value, function(key:Dynamic, item:Dynamic) {
- Global.array_push(strings, (key:String) + ' => ' + stringify(item));
- });
- return '[' + Global.implode(', ', strings) + ']';
- }
- if (value.is_object()) {
- if (value.method_exists('toString')) {
- return value.toString();
- }
- if (value.method_exists('__toString')) {
- return value.__toString();
- }
- if (Std.is(value, StdClass)) {
- if (Global.isset(Syntax.getField(value, 'toString')) && value.toString.is_callable()) {
- return value.toString();
- }
- var result = new NativeIndexedArray<String>();
- var data = Global.get_object_vars(value);
- for (key in data.array_keys()) {
- result.array_push('$key : ' + stringify(data[key]));
- }
- return '{ ' + Global.implode(', ', result) + ' }';
- }
- if (isFunction(value)) {
- return '<function>';
- }
- if (Std.is(value, HxClass)) {
- return '[class ' + getClassName((value:HxClass).phpClassName) + ']';
- } else {
- return '[object ' + getClassName(Global.get_class(value)) + ']';
- }
- }
- throw "Unable to stringify value";
- }
- static public inline function isNumber( value:Dynamic ) {
- return value.is_int() || value.is_float();
- }
- /**
- Check if specified values are equal
- **/
- public static function equal( left:Dynamic, right:Dynamic ) : Bool {
- if (isNumber(left) && isNumber(right)) {
- return Syntax.binop(left, '==', right);
- }
- return Syntax.binop(left, '===', right);
- }
- /**
- Concat `left` and `right` if both are strings or string and null.
- Otherwise return sum of `left` and `right`.
- **/
- public static function addOrConcat( left:Dynamic, right:Dynamic ) : Dynamic {
- if (left.is_string() || right.is_string()) {
- return (left:String) + (right:String);
- }
- return Syntax.binop(left, '+', right);
- }
- /**
- `Std.is()` implementation
- **/
- public static function is( value:Dynamic, type:HxClass ) : Bool {
- if (type == null) return false;
- var phpType = type.phpClassName;
- switch (phpType) {
- case 'Dynamic':
- return true;
- case 'Int':
- return (
- value.is_int()
- || (
- value.is_float()
- && Syntax.binop(Syntax.int(value), '==', value)
- && !Global.is_nan(value)
- )
- )
- && Global.abs(value) <= 2147483648;
- case 'Float':
- return value.is_float() || value.is_int();
- case 'Bool':
- return value.is_bool();
- case 'String':
- return value.is_string();
- case 'php\\NativeArray', 'php\\_NativeArray\\NativeArray_Impl_':
- return value.is_array();
- case 'Enum', 'Class':
- if (Std.is(value, HxClass)) {
- var valuePhpClass = (cast value:HxClass).phpClassName;
- var enumPhpClass = (cast HxEnum:HxClass).phpClassName;
- var isEnumType = Global.is_subclass_of(valuePhpClass, enumPhpClass);
- return (phpType == 'Enum' ? isEnumType : !isEnumType);
- }
- case _:
- if (value.is_object()) {
- var type:Class<Dynamic> = cast type;
- return Syntax.instanceof(value, type);
- }
- }
- return false;
- }
- /**
- Check if `value` is a `Class<T>`
- **/
- public static inline function isClass(value:Dynamic) : Bool {
- return Std.is(value, HxClass);
- }
- /**
- Check if `value` is an enum constructor instance
- **/
- public static inline function isEnumValue(value:Dynamic) : Bool {
- return Std.is(value, HxEnum);
- }
- /**
- Check if `value` is a function
- **/
- public static inline function isFunction(value:Dynamic) : Bool {
- return Std.is(value, Closure) || Std.is(value, HxClosure);
- }
- /**
- Check if `value` is an instance of `HxClosure`
- **/
- public static inline function isHxClosure(value:Dynamic) : Bool {
- return Std.is(value, HxClosure);
- }
- /**
- Performs `left >>> right` operation
- **/
- public static function shiftRightUnsigned( left:Int, right:Int ) : Int {
- if (right == 0) {
- return left;
- } else if (left >= 0) {
- return (left >> right);
- } else {
- return (left >> right) & (0x7fffffff >> (right - 1));
- }
- }
- /**
- Helper method to avoid "Cannot use temporary expression in write context" error for expressions like this:
- ```
- (new MyClass()).fieldName = 'value';
- ```
- **/
- static public function deref( value:Dynamic ) : Dynamic {
- return value;
- }
- /**
- Create Haxe-compatible anonymous structure of `data` associative array
- **/
- static public inline function createAnon( data:NativeArray ) : Dynamic {
- return new HxAnon(data);
- }
- /**
- Make sure specified class is loaded
- **/
- static public inline function ensureLoaded( phpClassName:String ) : Bool {
- return Global.class_exists(phpClassName) || Global.interface_exists(phpClassName);
- }
- /**
- Get `field` of a dynamic `value` in a safe manner (avoid exceptions on trying to get a method)
- **/
- static public function dynamicField( value:Dynamic, field:String ) : Dynamic {
- if(Global.method_exists(value, field)) {
- return closure(value, field);
- }
- if(Global.is_string(value)) {
- value = @:privateAccess new HxDynamicStr(value);
- }
- return Syntax.getField(value, field);
- }
- public static function dynamicString( str:String ) : HxDynamicStr {
- return @:privateAccess new HxDynamicStr(str);
- }
- }
- /**
- Class<T> implementation for Haxe->PHP internals.
- **/
- @:keep
- @:dox(hide)
- private class HxClass {
- public var phpClassName (default,null) : String;
- public function new( phpClassName:String ) : Void {
- this.phpClassName = phpClassName;
- }
- /**
- Magic method to call static methods of this class, when `HxClass` instance is in a `Dynamic` variable.
- **/
- @:phpMagic
- function __call( method:String, args:NativeArray ) : Dynamic {
- var callback = (phpClassName == 'String' ? (cast HxString:HxClass).phpClassName : phpClassName) + '::' + method;
- return Global.call_user_func_array(callback, args);
- }
- /**
- Magic method to get static vars of this class, when `HxClass` instance is in a `Dynamic` variable.
- **/
- @:phpMagic
- function __get( property:String ) : Dynamic {
- if (Boot.hasGetter(phpClassName, property)) {
- return Syntax.staticCall(phpClassName, 'get_$property');
- } else {
- return Syntax.getStaticField(phpClassName, property);
- }
- }
- /**
- Magic method to set static vars of this class, when `HxClass` instance is in a `Dynamic` variable.
- **/
- @:phpMagic
- function __set( property:String, value:Dynamic ) : Void {
- if (Boot.hasSetter(phpClassName, property)) {
- Syntax.staticCall(phpClassName, 'set_$property', value);
- } else {
- Syntax.setStaticField(phpClassName, property, value);
- }
- }
- }
- /**
- Base class for enum types
- **/
- @:keep
- @:dox(hide)
- private class HxEnum {
- static var singletons = new Map<String,HxEnum>();
- var tag : String;
- var index : Int;
- var params : NativeArray;
- /**
- Returns instances of constructors without arguments
- **/
- public static function singleton( enumClass:String, tag:String, index:Int ) : HxEnum {
- var key = '$enumClass::$tag';
- var instance = singletons.get(key);
- if (instance == null) {
- instance = Syntax.construct(enumClass, tag, index);
- singletons.set(key, instance);
- }
- return instance;
- }
- public function new( tag:String, index:Int, arguments:NativeArray = null ) : Void {
- this.tag = tag;
- this.index = index;
- params = (arguments == null ? new NativeArray() : arguments);
- }
- /**
- Get string representation of this `Class`
- **/
- public function toString() : String {
- return __toString();
- }
- /**
- PHP magic method to get string representation of this `Class`
- **/
- @:phpMagic
- public function __toString() : String {
- var result = tag;
- if (Global.count(params) > 0) {
- var strings = Global.array_map(function (item) return Boot.stringify(item), params);
- result += '(' + Global.implode(',', strings) + ')';
- }
- return result;
- }
- }
- /**
- `String` implementation
- **/
- @:keep
- @:dox(hide)
- private class HxString {
- public static function toUpperCase( str:String ) : String {
- return Global.strtoupper(str);
- }
- public static function toLowerCase( str:String ) : String {
- return Global.strtolower(str);
- }
- public static function charAt( str:String, index:Int) : String {
- if (index < 0 || index >= str.length) {
- return '';
- } else {
- return (str:NativeString)[index];
- }
- }
- public static function charCodeAt( str:String, index:Int) : Null<Int> {
- if (index < 0 || index >= str.length) {
- return null;
- } else {
- return Global.ord((str:NativeString)[index]);
- }
- }
- public static function indexOf( str:String, search:String, startIndex:Int = null ) : Int {
- if (startIndex == null) {
- startIndex = 0;
- } else if (startIndex < 0) {
- startIndex += str.length;
- }
- var index = Global.strpos(str, search, startIndex);
- return (index == false ? -1 : index);
- }
- public static function lastIndexOf( str:String, search:String, startIndex:Int = null ) : Int {
- var index = Global.strrpos(str, search, (startIndex == null ? 0 : startIndex - str.length));
- if (index == false) {
- return -1;
- } else {
- return index;
- }
- }
- public static function split( str:String, delimiter:String ) : Array<String> {
- if (delimiter == '') {
- return @:privateAccess Array.wrap(Global.str_split(str));
- } else {
- return @:privateAccess Array.wrap(Global.explode(delimiter, str));
- }
- }
- public static function substr( str:String, pos:Int, ?len:Int ) : String {
- if (pos < -str.length) {
- pos = 0;
- } else if (pos >= str.length) {
- return '';
- }
- if (len == null) {
- return Global.substr(str, pos);
- } else {
- var result = Global.substr(str, pos, len);
- return (result == false ? '' : result);
- }
- }
- public static function substring( str:String, startIndex:Int, ?endIndex:Int ) : String {
- if (endIndex == null) {
- endIndex = str.length;
- } else if (endIndex < 0) {
- endIndex = 0;
- }
- if (startIndex < 0) startIndex = 0;
- if (startIndex > endIndex) {
- var tmp = endIndex;
- endIndex = startIndex;
- startIndex = tmp;
- }
- var result = Global.substr(str, startIndex, endIndex - startIndex);
- return (result == false ? '' : result);
- }
- public static function toString( str:String ) : String {
- return str;
- }
- public static function fromCharCode( code:Int ) : String {
- return Global.chr(code);
- }
- }
- /**
- For Dynamic access which looks like String.
- Instances of this class should not be saved anywhere.
- Instead it should be used to immediately invoke a String field right after instance creation one time only.
- **/
- @:dox(hide)
- @:keep
- private class HxDynamicStr extends HxClosure {
- static var hxString : String = (cast HxString:HxClass).phpClassName;
- /**
- Returns HxDynamicStr instance if `value` is a string.
- Otherwise returns `value` as-is.
- **/
- static function wrap( value:Dynamic ) : Dynamic {
- if (value.is_string()) {
- return new HxDynamicStr(value);
- } else {
- return value;
- }
- }
- static inline function invoke( str:String, method:String, args:NativeArray ) : Dynamic {
- Global.array_unshift(args, str);
- return Global.call_user_func_array(hxString + '::' + method, args);
- }
- function new( str:String ) {
- super(str, null);
- }
- @:phpMagic
- function __get( field:String ) : Dynamic {
- switch (field) {
- case 'length':
- return (target:String).length;
- case _:
- func = field;
- return this;
- }
- }
- @:phpMagic
- function __call( method:String, args:NativeArray ) : Dynamic {
- return invoke(target, method, args);
- }
- /**
- @see http://php.net/manual/en/language.oop5.magic.php#object.invoke
- **/
- @:phpMagic
- override public function __invoke() {
- return invoke(target, func, Global.func_get_args());
- }
- /**
- Generates callable value for PHP
- **/
- override public function getCallback(eThis:Dynamic = null) : NativeIndexedArray<Dynamic> {
- if (eThis == null) {
- return Syntax.arrayDecl((this:Dynamic), func);
- }
- return Syntax.arrayDecl((new HxDynamicStr(eThis):Dynamic), func);
- }
- /**
- Invoke this closure with `newThis` instead of `this`
- **/
- override public function callWith( newThis:Dynamic, args:NativeArray ) : Dynamic {
- if (newThis == null) {
- newThis = target;
- }
- return invoke(newThis, func, args);
- }
- }
- /**
- Anonymous objects implementation
- **/
- @:keep
- @:dox(hide)
- 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
- function __get( name:String ) {
- return null;
- }
- @:phpMagic
- function __call( name:String, args:NativeArray ) : Dynamic {
- var method = Syntax.getField(this, name);
- Syntax.keepVar(method);
- return method(Syntax.splat(args));
- }
- }
- /**
- Closures implementation
- **/
- @:keep
- @:dox(hide)
- private class HxClosure {
- /** `this` for instance methods; php class name for static methods */
- var target : Dynamic;
- /** Method name for methods */
- var func : String;
- public function new( target:Dynamic, func:String ) : Void {
- this.target = target;
- this.func = func;
- //Force runtime error if trying to create a closure of an instance which happen to be `null`
- if (target.is_null()) {
- throw "Unable to create closure on `null`";
- }
- }
- /**
- @see http://php.net/manual/en/language.oop5.magic.php#object.invoke
- **/
- @:phpMagic
- public function __invoke() {
- return Global.call_user_func_array(getCallback(), Global.func_get_args());
- }
- /**
- Generates callable value for PHP
- **/
- public function getCallback(eThis:Dynamic = null) : NativeIndexedArray<Dynamic> {
- if (eThis == null) {
- eThis = target;
- }
- if (Std.is(eThis, StdClass)) {
- if (Std.is(eThis, HxAnon)) {
- return Syntax.getField(eThis, func);
- }
- }
- return Syntax.arrayDecl(eThis, func);
- }
- /**
- Check if this is the same closure
- **/
- public function equals( closure:HxClosure ) : Bool {
- return (target == closure.target && func == closure.func);
- }
- /**
- Invoke this closure with `newThis` instead of `this`
- **/
- public function callWith( newThis:Dynamic, args:NativeArray ) : Dynamic {
- return Global.call_user_func_array(getCallback(newThis), args);
- }
- }
- /**
- Special exception which is used to wrap non-throwable values
- **/
- @:keep
- @:dox(hide)
- private class HxException extends Exception {
- var e : Dynamic;
- public function new( e:Dynamic ) : Void {
- this.e = e;
- super(Boot.stringify(e));
- }
- }
|