Selaa lähdekoodia

PHP7 generator (#5845)

* [php7] Generate closure if static method passed as value

* [php7] TEnumParameter expression

* [php7] translate `super` to `parent`

* [php7] changed indentation to tabs in Globals.hx

* [php7] add basic NattiveArray/Array implementation

* [php7] Array 7 NativeArray implementation progress

* [php7] some tweaks for Array and NativeArray

* [php7] another pack of changes for Array & NativeArray

* [php7] `write_arg` functions refactoring

* [php7] refactoring of write_as_block and write_function

* [php7] instance dynamic methods

* [php7] static dynamic methods

* [php7] helper function: get_void

* [php7] fix static dynamic methods initialization

* [php7] `final` for classes

* [php7] `final` for methods

* [php7] Ref<T> to pass function args by reference

* [php] set_error_handler

* [php7] set_exception_handler

* [php7] --php-prefix implementation

* [php7] Invoke Boot initialization automatically upon loading any haxe-generated class

* [php7] tweaks in exceptions handling

* [php7] turned off null padding

* [php7] force constructor generation for some classes in root package

* [php7] force constructor generation for some classes in root package

* [php7] rename classes which use reserved words for class names

* [php7] rename namespaces which use keywords as their names

* [php7] generate index.php

* [php7] fix syntax error in Boot

* [php7] run Boot initialization before loading any other class

* [php7] trace() implementation and other std improvements

* [php7] handle `null` in strings concatenations

* [php7] handle `null` in strings concatenations

* [php7] Global.var_dump()

* [php7] fix Boot.stringify() for objects

* [php7] String.charAt(), String.split()

* [php7] new String()

* [php7] String methods implementation

* [php7] String.fromCharCode()

* [php7] fix Int and Float equality check

* [php7] Changed HxEnum fields to follow old genphp and reuse std code

* [php7] haxe.CallStack()

* [php7] fix static vars initialization in `-debug` mode

* [php] improved CallStack.exceptionStack()

* [php7] fix CallStack class/method reporting

* [php7] do not add CallStack.callStack() to result

* [php7] truncate exception stack to the place where exception was caught

* [php7] initial porting of root classes in std

* [php7] create separate implementation of haxe.CallStack

* [php7] fix accessing non-existent fields of anonymous objects

* [php7] Fix handle `null`s in += concatenations

* [php7] Support String fields for Dynamic values

* [php7] minor tweaks to Std.string() output format

* [php7] Make possible to call static methods on Class<T> instances contained in dynamic values

* [php7] fix optional arguments for dynamic methods

* [php7] Moved static methods from HxClass to Boot

* [php7] Register setters and getters to be able to use them with reflection

* [php7] Reflect (except compareMethods())

* [php7] fix typed cast

* [php7] HxClosure - custom class for closures to be able to compare them; Reflect.compareMethods()

* [php7] minor change dynamic method generation to follow HxClosure aproach

* [php7] changed Reflect.callMethod() for new HxClosure approach

* [php7] do not use HxClosure for anonymous functions

* [php7] fix TTypeExpr generation

* [php7] fix exceptions

* Merge branch 'development' into php7

* [php7] partial Type implementation

* [php7] Type.resolveClass()

* [php7] more Type implementations

* [php7] Type.getInstanceFields()

* [php7] Type.getClassFields()

* [php7] fix Type.getInstanceFields() & Type.getClassFields()

* [php7] Type.getEnumConstructs()

* [php7] Type.typeof()

* [php7] Type implemented

* [php7] Class constants for externs via @:phpClassConst

* [php7] Math

* [php7] Std.hx

* [php7] test suite

* [php7] Superglobals

* [php7] Sys

* [php7] preg_match & preg_match_all

* [php7] BytesData

* [php7] StringTools.fastCodeAt()

* [php7] fix ast generation for php7

* [php7] fix interface methods generation

* [php7] update php keywords list

* [php7] fix edge cases of `new Something()->field`

* [php7] fixes for closure calls

* [php7] special php7.PHP extern to reduce usage of `untyped`

* [php7] refactor code generation for php7.PHP methods

* [php7] allow local vars for second argument of PHP.instanceof()

* [php7] get rid of untyped code in Boot.hx

* [php7] get rid of untyped code in Boot.hx

* [php7] fix throwing native exceptions

* [php7] renamed php7.PHP to php7.Syntax

* [php7] make Array @:coreType again

* [php7] generate closures for blocks which cannot be parsed as-is in PHP

* [php7] wrap exprs like (new MyClass()).field = 10 in function calls to avoid php error "Cannot use temporary expression in write context"

* [php7] fix dynamic field access on `TNew` expressions

* [php7] fix for #5025

* [php7] add `parent` to the list of reserved keywords

* [php7] fix TCall on FClosure with casts

* [php7] fix ternary in ternary

* [php7] fix Reflect.field() for non-anonymous objects

* [php7] inline Boot.closure()

* [php7] fix Syntax.getField() and Syntax.setField() when field is defined with complex expression

* [php7] fix % for floats

* [php7] fix haxe.CallStack for internal php functions

* [php7] use common List implementation for now

* [php7] Syntax.call(), Syntax.keepVar()

* [php7] Get rid of untyped code in Reflect

* [php7] fix Array

* [php7] fix call acces to structures fields

* [php7] fix IntMap

* [php7] fix instantiation of empty structures

* [php7] use haxe.extern.AsVar

* [php7] php7.Syntax minor tweaks

* [php7] generate __toString() method if user defined a toString() method

* [php7] StringMap

* [php7] Do not generate imports for types in the same namespace

* [php7] EReg

* [php7] fix equality check for unknown types

* [php7] fix Array.splice()

* [php7] fix IntMap

* [php7] Syntax.binop()

* [php7] haxe.io.Bytes*, haxe.crypto.*

* [php7] fix bytes in haxe.io.*

* [php7] TestIO passed

* [php7] unset variables declared in loops

* [php7] moved unsets to beginnings of loops

* [php7] removed untyped code from StringTools

* [php7] fix EReg

* [php7] fix TCall for anonymous structures

* [php7] removed traces from Type

* [php7] fix `continue` and `break` generation

* [php7] fix StringTools.isEof()

* [php7] fix initialization of dynamic methods

* [php7] php7.Lib

* [php7] haxe.Json

* [php7] sys.FileSystem

* [php7] `-resource` compiler flag

* [php7] haxe.Int32

* [php7] keep Int64.toString()

* [php7] removed untyped code in Type

* [php7] fix Type.createEnum()

* [php7] fix Boot.hasGetter(), Boot.hasSetter()

* [php7] fix Boot.hasGetter(), Boot.hasSetter() again

* [php7] Syntax.getStaticField(), Syntax.setStaticField()

* [php7] fix Boot.is()

* [php7] TestReflect.testIs() passed

* [php7] fix Type.getClassName()

* [php7] TestReflect passed

* Do not treat Bool as enum in tests (fixes #5804)

* [php7] haxe.ds.ObjectMap

* [php7] TestSerialize passed

* [php7] rtti meta

* [php7] TestType passed

* [php7] fix __toString() generation

* [php7] fix changing array length via arr[bigIndex] = value

* [php7] fix DCE-ing toString() issue; Replace Boot.stringOrNull() with null coalescing operator

* [php7] fix Array.splice() for len < 0

* [php7] fix accessing String methods on anonymous structures

* [php7] fix Array.filter()

* [php7] fix BytesBuffer.add()

* [php7] fix EReg.replace()

* [php7] fix accessing static vars on classes stored to local variable

* [php7] fix Reflect.getProperty() for methods

* [php7] fix Reflect.field() for Class<Dynamic>

* [php7] fix StringTools

* [php7] fix strings comparison

* [php7] fix Type

* [php7] fix ArrayIterator

* [php7] fix concatenation for nulled non-string expressions

* [php7] fix static call on classes stored to vars

* [php7] fix concatenation with constant null

* [php7] fix dynamic methods on interfaces

* [php7] fix static var call inside of a cast

* [php7] fix creating closures of enum constructors

* [php7] fix StringMap.keys()

* [php7] fix Array.insert()

* [php7] fix Reflect.makeVasrArgs()

* [php7] fix array access for assignop operations

* [php7] fix Reflect.hasField() for Class<Dynamic>

* [php7] haxe.Utf8

* [php7] sys tests adjustments

* [php7] fix ternary/if generation for static inits

* [php7] revert TestReflect

* [php7] adjust sys tests for php7

* [php7] fix Sys.command()

* [php7] rewrite sys.io.Process

* [php7] sys.db.Mysql

* [php7] wip sqlite

* [php7] SQLite externs

* [php7] fix haxe.db

* [php7] generate parentheses around Syntax.binop()

* [php7] draft for genphp7.field_needs_rename

* [php7] rename fields which has same names as special PHP magic methods

* [php7] minor

* [php7] sqlite via PDO

* [php7] add missing @:phpMagic

* [php7] fix MysqlResultSet.results()

* [php7] added missing @:phpMagic to externs

* [php7] fix ReflectionProperty

* [php7] fix Bytes.toString()

* [php7] fix field types for mysql

* [php7] fix Mysql

* [php7] fix Mysql for `null` values

* [php7] fix Sqlite.quote()

* [php7] sqlite fix in progress

* [php7] use php7-sqlite3 for Sqlite

* [php7] fix SQLiteConnection.escape()

* [php7] fix SQLiteResultSet.hasNext()

* [php7] revert debug

* [php7] revert debug

* [php7] remove NativeXml for now

* [php7] travis

* [php7] travis

* [php7] travis

* [php7] travis

* [php7] travis

* [php7] -D php7 draft

* [php7] -D php7 done

* fix haxelib submodule

* fix indentation in haxe.io.Input

* [php7] fix RunCi

* [php7] fix FyleSystem for windows

* [php7] inline FileSystem.createDirectory()

* [php7] add `void` and `iterable` to keywords list (new in PHP 7.1)

* [php7] update extra

* [php7] fix extra
Alexander Kuzmenko 8 vuotta sitten
vanhempi
commit
4476787443
100 muutettua tiedostoa jossa 11606 lisäystä ja 57 poistoa
  1. 5 1
      .gitignore
  2. 18 1
      .travis.yml
  3. 2 2
      Makefile
  4. 6 1
      extra/ImportAll.hx
  5. 6 0
      extra/all.hxml
  6. 13 5
      src/context/common.ml
  7. 5 1
      src/context/meta.ml
  8. 3320 0
      src/generators/genphp7.ml
  9. 12 2
      src/main.ml
  10. 3 3
      src/optimization/analyzerTexpr.ml
  11. 1 1
      src/optimization/filters.ml
  12. 1 1
      src/typing/typer.ml
  13. 4 4
      std/DateTools.hx
  14. 1 1
      std/haxe/CallStack.hx
  15. 1 1
      std/haxe/Int64.hx
  16. 4 2
      std/haxe/Log.hx
  17. 7 2
      std/haxe/Serializer.hx
  18. 1 1
      std/haxe/Timer.hx
  19. 2 0
      std/haxe/io/BytesData.hx
  20. 17 17
      std/haxe/io/Input.hx
  21. 5 3
      std/haxe/rtti/Meta.hx
  22. 8 8
      std/haxe/xml/Parser.hx
  23. 13 0
      std/php7/ArrayAccess.hx
  24. 835 0
      std/php7/Boot.hx
  25. 12 0
      std/php7/Closure.hx
  26. 274 0
      std/php7/Const.hx
  27. 42 0
      std/php7/Error.hx
  28. 40 0
      std/php7/ErrorException.hx
  29. 42 0
      std/php7/Exception.hx
  30. 938 0
      std/php7/Global.hx
  31. 32 0
      std/php7/IteratorAggregate.hx
  32. 152 0
      std/php7/Lib.hx
  33. 67 0
      std/php7/NativeArray.hx
  34. 40 0
      std/php7/NativeAssocArray.hx
  35. 44 0
      std/php7/NativeIndexedArray.hx
  36. 31 0
      std/php7/NativeString.hx
  37. 9 0
      std/php7/Ref.hx
  38. 7 0
      std/php7/Resource.hx
  39. 4 0
      std/php7/RuntimeException.hx
  40. 9 0
      std/php7/Scalar.hx
  41. 168 0
      std/php7/Session.hx
  42. 6 0
      std/php7/StdClass.hx
  43. 60 0
      std/php7/SuperGlobal.hx
  44. 126 0
      std/php7/Syntax.hx
  45. 16 0
      std/php7/Throwable.hx
  46. 7 0
      std/php7/Traversable.hx
  47. 395 0
      std/php7/Web.hx
  48. 240 0
      std/php7/_std/Array.hx
  49. 92 0
      std/php7/_std/Date.hx
  50. 137 0
      std/php7/_std/EReg.hx
  51. 58 0
      std/php7/_std/Math.hx
  52. 179 0
      std/php7/_std/Reflect.hx
  53. 92 0
      std/php7/_std/Std.hx
  54. 51 0
      std/php7/_std/StringBuf.hx
  55. 205 0
      std/php7/_std/StringTools.hx
  56. 145 0
      std/php7/_std/Sys.hx
  57. 361 0
      std/php7/_std/Type.hx
  58. 142 0
      std/php7/_std/haxe/CallStack.hx
  59. 111 0
      std/php7/_std/haxe/Json.hx
  60. 68 0
      std/php7/_std/haxe/Resource.hx
  61. 88 0
      std/php7/_std/haxe/Utf8.hx
  62. 39 0
      std/php7/_std/haxe/crypto/Md5.hx
  63. 39 0
      std/php7/_std/haxe/crypto/Sha1.hx
  64. 39 0
      std/php7/_std/haxe/crypto/Sha224.hx
  65. 39 0
      std/php7/_std/haxe/crypto/Sha256.hx
  66. 98 0
      std/php7/_std/haxe/ds/IntMap.hx
  67. 82 0
      std/php7/_std/haxe/ds/ObjectMap.hx
  68. 74 0
      std/php7/_std/haxe/ds/StringMap.hx
  69. 206 0
      std/php7/_std/haxe/io/Bytes.hx
  70. 89 0
      std/php7/_std/haxe/io/BytesBuffer.hx
  71. 88 0
      std/php7/_std/haxe/io/BytesData.hx
  72. 79 0
      std/php7/_std/haxe/io/BytesInput.hx
  73. 57 0
      std/php7/_std/haxe/io/BytesOutput.hx
  74. 61 0
      std/php7/_std/haxe/io/FPHelper.hx
  75. 55 0
      std/php7/_std/haxe/zip/Compress.hx
  76. 45 0
      std/php7/_std/haxe/zip/Uncompress.hx
  77. 112 0
      std/php7/_std/sys/FileSystem.hx
  78. 237 0
      std/php7/_std/sys/db/Mysql.hx
  79. 191 0
      std/php7/_std/sys/db/Sqlite.hx
  80. 63 0
      std/php7/_std/sys/io/File.hx
  81. 82 0
      std/php7/_std/sys/io/FileInput.hx
  82. 72 0
      std/php7/_std/sys/io/FileOutput.hx
  83. 213 0
      std/php7/_std/sys/io/Process.hx
  84. 58 0
      std/php7/_std/sys/net/Host.hx
  85. 172 0
      std/php7/_std/sys/net/Socket.hx
  86. 71 0
      std/php7/db/Mysqli.hx
  87. 16 0
      std/php7/db/Mysqli_driver.hx
  88. 40 0
      std/php7/db/Mysqli_result.hx
  89. 35 0
      std/php7/db/Mysqli_stmt.hx
  90. 10 0
      std/php7/db/Mysqli_warning.hx
  91. 107 0
      std/php7/db/PDO.hx
  92. 8 0
      std/php7/db/PDOException.hx
  93. 26 0
      std/php7/db/PDOStatement.hx
  94. 28 0
      std/php7/db/SQLite3.hx
  95. 14 0
      std/php7/db/SQLite3Result.hx
  96. 16 0
      std/php7/db/SQLite3Stmt.hx
  97. 31 0
      std/php7/net/SslSocket.hx
  98. 64 0
      std/php7/reflection/ReflectionClass.hx
  99. 35 0
      std/php7/reflection/ReflectionFunctionAbstract.hx
  100. 35 0
      std/php7/reflection/ReflectionMethod.hx

+ 5 - 1
.gitignore

@@ -63,6 +63,7 @@
 /tests/unit/node_modules/
 
 /haxe.sublime*
+.idea
 build.bat
 /.vscode
 tests/unit/compile.php.hxml
@@ -73,6 +74,7 @@ tests/unit/unit.py
 tests/unit/unit.py.res1.txt
 tests/unit/unit.py.res2.bin
 tests/sys/bin/
+/tests/sys/dump/
 tests/optimization/dump/
 tests/misc/projects/*/*.n
 tests/unit/bin/
@@ -88,4 +90,6 @@ tests/misc/projects/Issue4070/cpp/
 /tests/misc/eventLoop/dump
 /tests/misc/eventLoop/eventLoop.py
 /tests/misc/eventLoop/php
-*.vscode/
+*.vscode/
+
+/tests/sys/temp

+ 18 - 1
.travis.yml

@@ -29,9 +29,13 @@ addons: &addons
 
 install_linux: &install_linux
   # Install neko and haxe dependencies
+  - sudo add-apt-repository ppa:avsm/ppa -y
+  - sudo apt-get update
   - sudo apt-get install -y
+      ocaml
       ocaml-native-compilers
-      camlp4
+      camlp4-extra
+      opam
       pkg-config
       libgc-dev
       libssl-dev
@@ -41,6 +45,9 @@ install_linux: &install_linux
       libmysqlclient-dev
       libsqlite3-dev
       libgtk2.0-dev
+  - opam init --auto-setup
+  - opam switch 4.02.3 -y
+  - eval `opam config env`
   # Install neko
   - travis_retry git clone https://github.com/HaxeFoundation/neko.git ~/neko
   - pushd ~/neko
@@ -131,6 +138,15 @@ matrix:
             g++-multilib
       install: *install_linux
 
+    - os: linux
+      env:
+        - TEST=php7
+      before_install:
+        - phpenv global "7.0"
+        # - sudo apt-get install php7-cli php7-mysql php7-sqlite -y || (sudo add-apt-repository ppa:ondrej/php -y && sudo apt-get update -y && sudo apt-get install  php7.0-cli php7.0-mysql php7.0-sqlite -y)
+        - php -v || true
+      install: *install_linux
+
     #######
     # osx #
     #######
@@ -149,6 +165,7 @@ script:
   - eval `ssh-agent -s` # for deployment to haxe.org
   - pushd tests
   -   mkdir ~/haxelib && haxelib setup ~/haxelib
+  -   haxelib install record-macros
   -   haxe -version
   -   haxe RunCi.hxml
   -   neko RunCi.n

+ 2 - 2
Makefile

@@ -58,7 +58,7 @@ MODULES=json version globals path context/meta syntax/ast display/displayTypes t
 	syntax/lexer context/common generators/genxml \
 	syntax/parser typing/abstract typing/typecore display/display optimization/optimizerTexpr \
 	optimization/optimizer typing/overloads typing/typeload generators/codegen generators/gencommon generators/genas3 \
-	generators/gencpp generators/genjs generators/genneko generators/genphp generators/genswf9 \
+	generators/gencpp generators/genjs generators/genneko generators/genphp generators/genphp7 generators/genswf9 \
 	generators/genswf generators/genjava generators/gencs generators/genpy macro/macroApi macro/interp generators/hlcode generators/hlopt generators/hlinterp generators/hl2c \
 	generators/genlua \
 	optimization/dce optimization/analyzerConfig optimization/analyzerTypes optimization/analyzerTexpr \
@@ -134,7 +134,7 @@ uninstall:
 	else \
 		rm -rf $(INSTALL_LIB_DIR); \
 	fi
-	
+
 
 # Modules
 

+ 6 - 1
extra/ImportAll.hx

@@ -29,8 +29,10 @@ class ImportAll {
 			haxe.macro.Compiler.define("doc_gen");
 		}
 		switch( pack ) {
+		case "php7":
+			if( !Context.defined("php7") ) return;
 		case "php":
-			if( !Context.defined("php") ) return;
+			if( !Context.defined("php") || Context.defined("php7") ) return;
 		case "neko":
 			if( !Context.defined("neko") ) return;
 		case "js":
@@ -83,6 +85,9 @@ class ImportAll {
 					case "haxe.remoting.SyncSocketConnection": if( !(Context.defined("neko") || Context.defined("php") || Context.defined("cpp")) ) continue;
 					case "sys.db.Sqlite" | "sys.db.Mysql" | "cs.db.AdoNet": continue;
 					}
+					if( Context.defined("php7") && cl.indexOf("php7.") == 0 ) {
+						cl = "php." + cl.substr("php7.".length);
+					}
 					Context.getModule(cl);
 				} else if( sys.FileSystem.isDirectory(p + "/" + file) )
 					run(full);

+ 6 - 0
extra/all.hxml

@@ -19,6 +19,12 @@
 
 --next
 
+-D php7
+-php all_php7
+-xml php7.xml
+
+--next
+
 -php all_php
 -xml php.xml
 

+ 13 - 5
src/context/common.ml

@@ -316,6 +316,8 @@ let get_signature com =
 		com.defines_signature <- Some s;
 		s
 
+let php7 com = com.platform = Php && PMap.exists "php7" com.defines
+
 module CompilationServer = struct
 	type cache = {
 		c_haxelib : (string list, string list) Hashtbl.t;
@@ -705,11 +707,17 @@ let get_config com =
 			pf_reserved_type_paths = [([],"Object");([],"Error")];
 		}
 	| Php ->
-		{
-			default_config with
-			pf_static = false;
-			pf_pad_nulls = true;
-		}
+		if php7 com then
+			{
+				default_config with
+				pf_static = false;
+			}
+		else
+			{
+				default_config with
+				pf_static = false;
+				pf_pad_nulls = true;
+			}
 	| Cpp ->
 		{
 			default_config with

+ 5 - 1
src/context/meta.ml

@@ -117,6 +117,8 @@ type strict_meta =
 	| Overload
 	| PhpConstants
 	| PhpGlobal
+	| PhpClassConst
+	| PhpMagic
 	| PrivateAccess
 	| Property
 	| Protected
@@ -307,7 +309,9 @@ let get_info = function
 	| Optional -> ":optional",("Marks the field of a structure as optional",[UsedOn TClassField])
 	| Overload -> ":overload",("Allows the field to be called with different argument types",[HasParam "Function specification (no expression)";UsedOn TClassField])
 	| PhpConstants -> ":phpConstants",("Marks the static fields of a class as PHP constants, without $",[Platform Php;UsedOn TClass])
-	| PhpGlobal -> ":phpGlobal",("Puts the static fields of a class in the global PHP namespace",[Platform Php;UsedOn TClass])
+	| 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])
 	| 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])

+ 3320 - 0
src/generators/genphp7.ml

@@ -0,0 +1,3320 @@
+(**
+	Compatible with PHP 7+
+*)
+
+open Ast
+open Type
+open Common
+open Meta
+open Globals
+
+let debug = ref false
+
+(**
+	Escape string for constant strings generation.
+	Copy-pasted from genphp.
+*)
+let escape_bin s =
+	let b = Buffer.create 0 in
+	for i = 0 to String.length s - 1 do
+		match Char.code (String.unsafe_get s i) with
+		| c when c = Char.code('\\') || c = Char.code('"') || c = Char.code('$') ->
+			Buffer.add_string b "\\";
+			Buffer.add_char b (Char.chr c)
+		| c when c < 32 ->
+			Buffer.add_string b (Printf.sprintf "\\x%.2X" c)
+		| c ->
+			Buffer.add_char b (Char.chr c)
+	done;
+	Buffer.contents b
+
+(**
+	Write resources passed to compiler via `-resource` flag
+	Copy-pasted from genphp
+*)
+let write_resource dir name data =
+	let rdir = dir ^ "/res" in
+	if not (Sys.file_exists dir) then Unix.mkdir dir 0o755;
+	if not (Sys.file_exists rdir) then Unix.mkdir rdir 0o755;
+	let name = Codegen.escape_res_name name false in
+	let ch = open_out_bin (rdir ^ "/" ^ name) in
+	output_string ch data;
+	close_out ch
+
+(**
+	Get list of keys in Hashtbl
+*)
+let hashtbl_keys tbl = Hashtbl.fold (fun key _ lst -> key :: lst) tbl []
+
+(**
+	@return List of items in `list1` which `list2` does not contain
+*)
+let diff_lists list1 list2 = List.filter (fun x -> not (List.mem x list2)) list1
+
+(**
+	Type path for native PHP Exception class
+*)
+let native_exception_path = ([], "Throwable")
+(**
+	Type path for Haxe exceptions wrapper
+*)
+let hxexception_type_path = (["php"; "_Boot"], "HxException")
+(**
+	Type path of `php.Boot`
+*)
+let boot_type_path = (["php"], "Boot")
+(**
+	Type path of the base class for all enums: `php.Boot.HxEnum`
+*)
+let hxenum_type_path = (["php"; "_Boot"], "HxEnum")
+(**
+	Type path of the implementation class for `Class<Dynamic>`
+*)
+let hxclass_type_path = (["php"; "_Boot"], "HxClass")
+(**
+	Type path of the implementation class for `String`
+*)
+let hxstring_type_path = (["php"; "_Boot"], "HxString")
+(**
+	Type path of the special implementation class for `String`
+	which is used when Dynamic value is suspected to be a string
+*)
+let hxdynamicstr_type_path = (["php"; "_Boot"], "HxDynamicStr")
+(**
+	Type path of the implementation class for anonymous objects
+*)
+let hxanon_type_path = (["php"; "_Boot"], "HxAnon")
+(**
+	Type path of the implementation class for closures
+*)
+let hxclosure_type_path = (["php"; "_Boot"], "HxClosure")
+(**
+	Type path for special PHP extern class to support specific language expressions
+*)
+let syntax_type_path = (["php"], "Syntax")
+(**
+	Special abstract which enables passing function arguments and return value by reference
+*)
+let ref_type_path = (["php"], "Ref")
+(**
+	Type path of the implementation class for `Array<T>`
+*)
+let array_type_path = ([], "Array")
+(**
+	Type path of the implementation class for `Array<T>`
+*)
+let native_array_type_path = (["php"], "NativeArray")
+(**
+	Type path of the `Void`
+*)
+let void_type_path = ([], "Void")
+(**
+	Type path of the `Bool`
+*)
+let bool_type_path = ([], "Bool")
+
+(**
+	Stub to use when you need a `Ast.pos` instance, but don't have one
+*)
+let dummy_pos = { pfile = ""; pmin = 0; pmax = 0 }
+
+(**
+	Check if specified string is a reserved word in PHP
+*)
+let is_keyword str =
+	match String.lowercase str with
+		| "__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"
+			-> true
+		| _ -> false
+
+(**
+	Check if specified type is Void
+*)
+let is_void_type t = match follow t with TAbstract ({ a_path = void_type_path }, _) -> true | _ -> false
+
+(**
+	Check if specified type is Bool
+*)
+let is_bool_type t = match follow t with TAbstract ({ a_path = bool_type_path }, _) -> true | _ -> false
+
+(**
+	Check if specified type is php.NativeArray
+*)
+let is_native_array_type t = match follow t with TAbstract ({ a_path = native_array_type_path }, _) -> true | _ -> false
+
+(**
+	If `name` is not a reserved word in PHP then `name` is returned as-is.
+	Otherwise this method returns another string, which can be used instead of `name`
+*)
+let get_real_name name = if is_keyword name then name ^ "_hx" else name
+
+(**
+	If `path` contains some reserved in PHP words, they will be replaced with allowed words.
+*)
+let get_real_path path = List.map get_real_name path
+
+(**
+	Resolve real type (bypass abstracts and typedefs)
+*)
+let rec follow = Abstract.follow_with_abstracts
+
+let prefix = ref None
+(**
+	Returns value of `--php-prefix` compiler flag
+*)
+let get_php_prefix ctx =
+	match !prefix with
+		| Some prefix -> prefix
+		| None ->
+			let lst =
+				match ctx.php_prefix with
+					| None -> []
+					| Some str ->
+						if String.length str = 0 then
+							[]
+						else
+							Str.split (Str.regexp "\\.") str
+			in
+			prefix := Some lst;
+			lst
+
+(**
+	Adds packages specified by `--php-prefix` to `type_path`.
+	E.g. if `--php-prefix some.sub` and `type_path` is `(["pack"], "MyClass")`, then this function
+	will return `(["some", "sub", "pack"], "MyClass")`
+*)
+let add_php_prefix ctx type_path =
+	match type_path with
+		| (pack, name) -> ((get_php_prefix ctx) @ pack, name)
+
+(**
+	If `expr` is a TCast returns underlying expression (recursively bypassing nested casts).
+	Otherwise returns `expr` as is.
+*)
+let rec reveal_expr expr =
+	match expr.eexpr with
+		| TCast (e, _) -> reveal_expr e
+		| TMeta (_, e) -> reveal_expr e
+		| _ -> expr
+
+(**
+	@return Error message with position information
+*)
+let error_message pos message = (Lexer.get_error_pos (Printf.sprintf "%s:%d:") pos) ^ ": " ^ message
+
+(**
+	Terminates compiler process and prints user-friendly instructions about filing an issue in compiler repo.
+*)
+let fail hxpos mlpos =
+	match mlpos with
+		| (file, line, _, _) ->
+			Printf.printf "%s\n" (error_message hxpos "Unexpected expression. Please submit an issue with expression example and following information:");
+			Printf.printf "%s:%d\n" file line;
+			assert false
+
+(**
+	Print compilation error message and abort compilation process.
+*)
+let error_and_exit pos message =
+	Printf.printf "%s" (error_message pos message);
+	exit 1
+
+(**
+	Check if `target` is a `Dynamic` type
+*)
+let rec is_dynamic_type (target:Type.t) = match follow target with TDynamic _ -> true | _ -> false
+
+(**
+	Check if `target` is `php.Ref`
+*)
+let is_ref (target:Type.t) = match target with TAbstract ({ a_path = type_path }, _) -> type_path = ref_type_path | _ -> false
+
+(**
+	Check if `field` is a `dynamic function`
+*)
+let rec is_dynamic_method (field:tclass_field) =
+	match field.cf_kind with
+		| Method MethDynamic -> true
+		| _ -> false
+
+(**
+	Check if specified expression is of `Dynamic` type
+*)
+let is_dynamic expr = is_dynamic_type expr.etype
+
+(**
+	Check if specified expression is of `Int` type
+*)
+let is_int expr = match follow expr.etype with TAbstract ({ a_path = ([], "Int") }, _) -> true | _ -> false
+
+(**
+	Check if specified expression is of `Float` type
+*)
+let is_float expr = match follow expr.etype with TAbstract ({ a_path = ([], "Float") }, _) -> true | _ -> false
+
+(**
+	Check if specified type is String
+*)
+let is_string_type t = match follow t with TInst ({ cl_path = ([], "String") }, _) -> true | _ -> false
+
+(**
+	Check if specified expression is of String type
+*)
+let is_string expr = is_string_type expr.etype
+
+(**
+	Check if `expr` is an access to a method of special `php.PHP` class
+*)
+let is_lang_extern expr =
+	match expr.eexpr with
+		| TField ({ eexpr = TTypeExpr (TClassDecl { cl_path = path }) }, _) when path = syntax_type_path -> true
+		| _ -> false
+
+(**
+	Check if specified type is actually a generic parameter
+*)
+let is_generic_parameter (target:Type.t) =
+	match follow target with
+		| TInst ({ cl_kind = KTypeParameter _ }, _) -> true
+		| _ -> false
+
+(**
+	Check if `target` type cannot be clarified on compilation
+*)
+let is_unknown_type (target:Type.t) = is_dynamic_type target || is_generic_parameter target
+
+(**
+	Check if `expr1` and `expr2` can be reliably checked for equality only with `Boot.equal()`
+*)
+let need_boot_equal expr1 expr2 =
+	(is_int expr1 && (is_float expr2 || is_unknown_type expr2.etype))
+	|| (is_float expr1 && (is_int expr2 || is_unknown_type expr2.etype))
+	|| (is_unknown_type expr1.etype && (is_int expr2 || is_float expr2))
+	|| (is_unknown_type expr1.etype && is_unknown_type expr2.etype)
+
+(**
+	@return `Type.t` instance for `Void`
+*)
+let void = ref None
+let get_void ctx : Type.t =
+	match !void with
+		| Some value -> value
+		| None ->
+			let find com_type =
+				match com_type with
+					| TAbstractDecl ({ a_path = ([], "Void") } as abstr) -> void := Some (TAbstract (abstr, []));
+					| _ -> ()
+			in
+			List.iter find ctx.types;
+			match !void with
+				| Some value -> value
+				| None -> fail dummy_pos __POS__
+
+(**
+	@return `tclass` instance for `php.Boot`
+*)
+let boot = ref None
+let get_boot ctx : tclass =
+	match !boot with
+		| Some value -> value
+		| None ->
+			let find com_type =
+				match com_type with
+					| TClassDecl ({ cl_path = path } as cls) when path = boot_type_path -> boot := Some cls;
+					| _ -> ()
+			in
+			List.iter find ctx.types;
+			match !boot with
+				| Some value -> value
+				| None -> fail dummy_pos __POS__
+
+(**
+	@return `expr` wrapped in parenthesis
+*)
+let parenthesis expr = {eexpr = TParenthesis expr; etype = expr.etype; epos = expr.epos}
+
+(**
+	Check if `current` binary should be surrounded with parenthesis
+*)
+let need_parenthesis_for_binop current parent =
+	if current = parent then
+		false
+	else
+		match (current, parent) with
+			| (_, OpAssign) -> false
+			| (_, OpAssignOp _) -> false
+			| (OpAdd, OpSub) -> false
+			| (OpSub, OpAdd) -> false
+			| (OpMult, OpDiv) -> false
+			| (OpDiv, OpMult) -> false
+			| (OpMult, OpAdd) -> false
+			| (OpMult, OpSub) -> false
+			| (OpDiv, OpAdd) -> false
+			| (OpDiv, OpSub) -> false
+			| _ -> true
+
+(**
+	Check if specified expression may require dereferencing if used as "temporary expression"
+*)
+let needs_dereferencing expr =
+	let rec is_create target_expr =
+		match target_expr.eexpr with
+			| TParenthesis e -> is_create e
+			| TCast (e, _) -> is_create e
+			| TNew _ -> true
+			| TArrayDecl _ -> true
+			| TObjectDecl _ -> true
+			| _ -> false
+	in
+	match expr.eexpr with
+		| TField (target_expr, _) -> is_create target_expr
+		| TArray (target_expr, _) -> is_create target_expr
+		| _ -> false
+
+(**
+	@return (arguments_list, return_type)
+*)
+let get_function_signature (field:tclass_field) : (string * bool * Type.t) list * Type.t =
+	match follow field.cf_type with
+		| TFun (args, return_type) -> (args, return_type)
+		| _ -> fail field.cf_pos __POS__
+
+(**
+	Check if `target` is 100% guaranteed to be a scalar type in PHP.
+	Inversion of `is_sure_scalar` does not guarantee `target` is not scalar.
+*)
+let is_sure_scalar (target:Type.t) =
+	match follow target with
+		| TInst ({ cl_path = ([], "String") }, _) -> true
+		| TAbstract (abstr, _) ->
+			(match abstr.a_path with
+				| ([],"Int") -> true
+				| ([],"Float") -> true
+				| ([],"Bool") -> true
+				| _ -> false
+			)
+		| _ -> false
+
+(**
+	Indicates if `expr` is guaranteed to be an access to a `var` field.
+*)
+let is_sure_var_field_access expr =
+	match (reveal_expr expr).eexpr with
+		| TField (_, FStatic (_, { cf_kind = Var _ })) -> true
+		| TField (_, FInstance (_, _, { cf_kind = Var _ })) -> true
+		(* | TField (_, FAnon { cf_kind = Var _ }) -> true *) (* Sometimes we get anon access to non-anonymous objects *)
+		| _ -> false
+
+(**
+	Check if specified unary operation modifies value in place
+*)
+let is_modifying_unop op =
+	match op with
+		| Increment
+		| Decrement -> true
+		| _ -> false
+
+(**
+	Indicates whether `expr` is a field access which should be generated as global namespace function
+*)
+let is_php_global expr =
+	match expr.eexpr with
+		| TField (_, FStatic ({ cl_extern = true; cl_meta = meta }, _)) -> Meta.has Meta.PhpGlobal meta
+		| _ -> false
+
+(**
+	Indicates whether `expr` is a field access which should be generated as class constant access
+*)
+let is_php_class_const expr =
+	match expr.eexpr with
+		| TField (_, FStatic ({ cl_extern = true }, { cf_meta = meta; cf_kind = Var _ })) ->
+			Meta.has Meta.PhpClassConst meta
+		| _ -> false
+
+(**
+	Check if specified enum constructor has arguments
+*)
+let is_enum_constructor_with_args (constructor:tenum_field) =
+	match follow constructor.ef_type with
+		| TFun _ -> true
+		| _ -> false
+
+(**
+	Check if `target` is 100% guaranteed to be or extend an extern class.
+	Inversion of `sure_extends_extern` does not guarantee `target` does not extend an extern class.
+*)
+let rec sure_extends_extern (target:Type.t) =
+	match follow target with
+		| TInst ({ cl_path = ([], "String") }, _) -> false
+		| TInst ({ cl_extern = true }, _) -> true
+		| TInst ({ cl_super = Some (tsuper, params) }, _) -> sure_extends_extern (TInst (tsuper,params))
+		| _ -> false
+
+(**
+	@return `opt` value or `default` if `opt` is None
+*)
+let get_option_value (opt:'a option) default =
+	match opt with
+		| None -> default
+		| Some value -> value
+
+(**
+	@param path Something like [ "/some/path/first_dir_to_create"; "nested_level1"; "nested_level2" ]
+	@return String representation of created path (E.g. "/some/path/first_dir_to_create/nested_level1/nested_level2")
+*)
+let create_dir_recursive (path:string list) =
+	let rec create dir nested_dirs =
+		if not (Sys.file_exists dir) then (Unix.mkdir dir 0o755);
+		match nested_dirs with
+			| [] -> ();
+			| next :: rest -> create (dir ^ "/" ^ next) rest
+	in
+	match path with
+		| [] -> "";
+		| root :: rest ->
+			create root rest;
+			(String.concat "/" path)
+
+(**
+	@return String representation of specified type path. E.g. returns "\example\Test" for (["example"], "Test")
+*)
+let get_full_type_name ?escape ?omit_first_slash (type_path:path) =
+	let name =
+		match type_path with
+			| (module_path, type_name) ->
+				let parts =
+					match omit_first_slash with
+						| Some true -> get_real_path module_path
+						| _ -> "" :: get_real_path module_path
+				in
+				(String.concat "\\" parts) ^ "\\" ^ type_name
+	in
+	match escape with
+		| Some true -> String.escaped name
+		| _ -> name
+
+(**
+	Check if `target` is or implements native PHP `Throwable` interface
+*)
+let rec is_native_exception (target:Type.t) =
+	match follow target with
+		| TInst ({ cl_path = path }, _) when path = native_exception_path -> true
+		| TInst ({ cl_super = parent ; cl_implements = interfaces ; cl_path = path }, _) ->
+			let (parent, params) =
+				match parent with
+					| Some (parent, params) -> (Some parent, params)
+					| None -> (None, [])
+			in
+			let found = ref false in
+			List.iter
+				(fun (cls, params) ->
+					if not !found then
+						found := is_native_exception (TInst (cls, params))
+				)
+				interfaces;
+			if !found then
+				true
+			else
+				(match parent with
+					| Some parent -> is_native_exception (TInst (parent, params))
+					| None -> false
+				)
+		| _ -> false
+
+(**
+	@return Short type name. E.g. returns "Test" for (["example"], "Test")
+*)
+let get_type_name (type_path:path) = match type_path with (_, type_name) -> type_name
+
+(**
+	@return E.g. returns ["example"] for (["example"], "Test")
+*)
+let get_module_path (type_path:path) = match type_path with (module_path, _) -> module_path
+
+(**
+	@return PHP visibility keyword.
+*)
+let get_visibility (meta:metadata) = if Meta.has Meta.Protected meta then "protected" else "public"
+
+(**
+	Writes arguments list to output buffer
+*)
+let rec write_args buffer arg_writer (args:'a) =
+	match args with
+		| [] -> ()
+		| [arg] -> arg_writer arg
+		| arg :: rest ->
+			arg_writer arg;
+			Buffer.add_string buffer ", ";
+			write_args buffer arg_writer rest
+
+(**
+	Check if specified field is a var with non-constant expression
+*)
+let is_var_with_nonconstant_expr (field:tclass_field) =
+	match field.cf_kind with
+		| Var _ ->
+			(match field.cf_expr with
+				| None -> false
+				| Some ({eexpr = TConst _ }) -> false
+				| Some _ -> true
+			)
+		| Method _ -> false
+
+(**
+	@return New TBlock expression which is composed of setting default values for optional arguments and function body.
+*)
+let inject_defaults (ctx:Common.context) (func:tfunc) =
+	let rec inject args body_exprs =
+		match args with
+			| [] -> body_exprs
+			| (_, None) :: rest -> inject rest body_exprs
+			| (_, Some TNull) :: rest -> inject rest body_exprs
+			| (var, Some const) :: rest ->
+				let expr = Codegen.set_default ctx var const func.tf_expr.epos in
+			 	expr :: (inject rest body_exprs)
+	in
+	let exprs =
+		match func.tf_expr.eexpr with
+			| TBlock exprs -> inject func.tf_args exprs
+			| _ -> inject func.tf_args [ func.tf_expr ]
+	in
+	{
+		eexpr = TBlock exprs;
+		etype = follow func.tf_expr.etype;
+		epos  = func.tf_expr.epos;
+	}
+
+(**
+	Check if `expr` is a constant string
+*)
+let is_constant_string expr =
+	match expr.eexpr with
+		| TConst (TString _) -> true
+		| _ -> false
+
+(**
+	Check if `expr` is a constant null
+*)
+let is_constant_null expr =
+	match expr.eexpr with
+		| TConst TNull -> true
+		| _ -> false
+
+(**
+	Check if `expr` is a constant
+*)
+let is_constant expr =
+	match expr.eexpr with
+		| TConst _ -> true
+		| _ -> false
+
+(**
+	Check if `expr` is a concatenation
+*)
+let is_concatenation expr =
+	match expr.eexpr with
+		| TBinop (OpAdd, expr1, expr2) -> (is_string expr1) || (is_string expr2)
+		| _ -> false
+
+(**
+	Check if provided expression is a binary operation
+*)
+let is_binop expr = match expr.eexpr with TBinop _ -> true | _ -> false
+
+(**
+	Check if provided expression is an assignment binary operation
+*)
+let is_binop_assign expr =
+	match expr.eexpr with
+		| TBinop (operation, _, _) ->
+			(match operation with
+				| OpAssign | OpAssignOp _ -> true
+				| _ -> false
+			)
+		| _ -> false
+
+(**
+	Check if specified expression is field access or array access
+*)
+let is_access expr =
+	match expr.eexpr with
+		| TField _ | TArray _ -> true
+		| _ -> false
+
+(**
+	Indicates if `expr` is actually a call to Haxe->PHP magic function
+	@see http://old.haxe.org/doc/advanced/magic#php-magic
+*)
+let is_magic expr =
+	match expr.eexpr with
+	| TCall ({ eexpr = TLocal { v_name = name }}, _) ->
+		(match name with
+			| "__php__" -> true
+			| "__call__" -> true
+			| "__physeq__" -> true
+			| "__var__" -> true
+			| _ -> false
+		)
+	| _ -> false
+
+(**
+	Adds `return` expression to block if it does not have one already
+*)
+let ensure_return_in_block block_expr =
+	match block_expr.eexpr with
+		| TBlock [] -> fail block_expr.epos __POS__
+		| TBlock exprs ->
+			let reversed = List.rev exprs in
+			let last_expr = List.hd reversed in
+			let return_expr = { last_expr with eexpr = TReturn (Some last_expr) } in
+			let reversed = return_expr::(List.tl reversed) in
+			{ block_expr with eexpr = TBlock (List.rev reversed) }
+		| _ -> fail block_expr.epos __POS__
+
+(**
+	Check if specified type has rtti meta
+*)
+let has_rtti_meta ctx mtype =
+	match Codegen.build_metadata ctx mtype with
+		| None -> false
+		| Some _ -> true
+
+(**
+	Check if this var accesses and meta combination should generate a variable
+*)
+let is_real_var field =
+	if Meta.has IsVar field.cf_meta then
+		true
+	else
+		match field.cf_kind with
+			| Var { v_read = read; v_write = write } -> read = AccNormal || write = AccNormal
+			| _ -> false
+
+(**
+	Check if user-defined field has the same name as one of php magic methods, but with not compatible signature.
+*)
+let field_needs_rename field =
+	match field.cf_kind with
+		| Var _ -> false
+		| Method _ ->
+			match field.cf_name with
+				| "__construct" | "__destruct" | "__call" | "__callStatic" | "__get" | "__set" | "__isset"
+				| "__unset" | "__sleep" | "__wakeup" | "__toString" | "__invoke" | "__set_state" | "__clone"
+				| "__debugInfo" -> not (Meta.has Meta.PhpMagic field.cf_meta)
+				| _ -> false
+(**
+	Get valid `field` name.
+*)
+let field_name field =
+	if field_needs_rename field then
+		"__hx__renamed" ^ field.cf_name
+	else
+		field.cf_name
+
+(**
+	PHP DocBlock types
+*)
+type doc_type =
+	| DocVar of string * (string option) (* (type name, description) *)
+	| DocMethod of (string * bool * t) list * t * (string option) (* (arguments, return type, description) *)
+| DocClass of string option
+
+(**
+	Common interface for module_type instances
+*)
+class virtual type_wrapper (type_path:path) (meta:metadata) (needs_generation:bool) =
+	object (self)
+		(**
+			Indicates if this type should be rendered to corresponding php file
+		*)
+		method needs_generation = needs_generation
+		(**
+			Indicates if class initialization method should be executed upon class loaded
+		*)
+		method virtual needs_initialization : bool
+		(**
+			Returns hx source file name where this type was declared
+		*)
+		method virtual get_source_file : string
+		(**
+			Returns `Type.module_type` instance for this type
+		*)
+		method virtual get_module_type : module_type
+		(**
+			Returns expression of a user-defined static __init__ method
+			@see http://old.haxe.org/doc/advanced/magic#initialization-magic
+		*)
+		method get_magic_init : texpr option = None
+		(**
+			Namespace path. E.g. ["some"; "pack"] for "some.pack.MyType"
+		*)
+		method get_namespace = get_module_path type_path
+		(**
+			Short type name. E.g. `SomeType` for `pack.SomeType`
+		*)
+		method get_name = get_type_name type_path
+		(**
+			Full type path
+		*)
+		method get_type_path = type_path
+	end
+
+(**
+	TClassDecl
+*)
+class class_wrapper (cls) =
+	object (self)
+		inherit type_wrapper cls.cl_path cls.cl_meta (not cls.cl_extern)
+		(**
+			Indicates if class initialization method should be executed upon class loaded
+		*)
+		method needs_initialization =
+			(* Interfaces may need initialization only for RTTI meta data.
+				But that meta is written in `class_wrapper#write_rtti_meta` *)
+			if cls.cl_interface then
+				false
+			else
+				match cls.cl_init with
+					| Some _ -> true
+					| None ->
+						let needs = ref false in
+						PMap.iter
+							(fun _ field ->
+								(* Check static vars with non-constant expressions *)
+								if not !needs then needs := is_var_with_nonconstant_expr field;
+								(* Check static dynamic functions *)
+								if not !needs then needs := is_dynamic_method field
+							)
+							cls.cl_statics;
+						!needs
+		(**
+			Returns expression of a user-defined static __init__ method
+			@see http://old.haxe.org/doc/advanced/magic#initialization-magic
+		*)
+		method get_magic_init = cls.cl_init
+		(**
+			Returns hx source file name where this type was declared
+		*)
+		method get_source_file = cls.cl_pos.pfile
+		(**
+			Returns `Type.module_type` instance for this type
+		*)
+		method get_module_type = TClassDecl cls
+	end
+
+(**
+	TEnumDecl
+*)
+class enum_wrapper (enm) =
+	object (self)
+		inherit type_wrapper enm.e_path enm.e_meta (not enm.e_extern)
+		(**
+			Indicates if class initialization method should be executed upon class loaded
+		*)
+		method needs_initialization = false
+		(**
+			Returns hx source file name where this type was declared
+		*)
+		method get_source_file = enm.e_pos.pfile
+		(**
+			Returns `Type.module_type` instance for this type
+		*)
+		method get_module_type = TEnumDecl enm
+	end
+
+(**
+	TTypeDecl
+*)
+class typedef_wrapper (tdef) =
+	object (self)
+		inherit type_wrapper tdef.t_path tdef.t_meta false
+		(**
+			Indicates if class initialization method should be executed upon class loaded
+		*)
+		method needs_initialization = false
+		(**
+			Returns hx source file name where this type was declared
+		*)
+		method get_source_file = tdef.t_pos.pfile
+		(**
+			Returns `Type.module_type` instance for this type
+		*)
+		method get_module_type = TTypeDecl tdef
+	end
+
+(**
+	TAbstractDecl
+*)
+class abstract_wrapper (abstr) =
+	object (self)
+		inherit type_wrapper abstr.a_path abstr.a_meta false
+		(**
+			Indicates if class initialization method should be executed upon class loaded
+		*)
+		method needs_initialization = false
+		(**
+			Returns hx source file name where this type was declared
+		*)
+		method get_source_file = abstr.a_pos.pfile
+		(**
+			Returns `Type.module_type` instance for this type
+		*)
+		method get_module_type = TAbstractDecl abstr
+	end
+
+(**
+	type_wrapper for classes
+*)
+let classes = Hashtbl.create 1000
+let get_class_wrapper cls  : type_wrapper =
+	try
+		let wrapper = Hashtbl.find classes cls in
+		wrapper
+	with
+		| Not_found ->
+			let wrapper = new class_wrapper cls in
+			Hashtbl.add classes cls wrapper;
+			wrapper
+		| e -> raise e
+
+(**
+	type_wrapper for enums
+*)
+let enums = Hashtbl.create 200
+let get_enum_wrapper enm : type_wrapper=
+	try
+		let wrapper = Hashtbl.find enums enm in
+		wrapper
+	with
+		| Not_found ->
+			let wrapper = new enum_wrapper enm in
+			Hashtbl.add enums enm wrapper;
+			wrapper
+		| e -> raise e
+
+(**
+	type_wrapper for typedefs
+*)
+let typedefs = Hashtbl.create 200
+let get_typedef_wrapper typedef : type_wrapper =
+	try
+		let wrapper = Hashtbl.find typedefs typedef in
+		wrapper
+	with
+		| Not_found ->
+			let wrapper = new typedef_wrapper typedef in
+			Hashtbl.add typedefs typedef wrapper;
+			wrapper
+		| e -> raise e
+
+(**
+	type_wrapper for abstracts
+*)
+let abstracts = Hashtbl.create 200
+let get_abstract_wrapper abstr : type_wrapper =
+	try
+		let wrapper = Hashtbl.find abstracts abstr in
+		wrapper
+	with
+		| Not_found ->
+			let wrapper = new abstract_wrapper abstr in
+			Hashtbl.add abstracts abstr wrapper;
+			wrapper
+		| e -> raise e
+
+(**
+	Returns wrapper for module_type.
+	Caches wrappers so that each type will always return the same wrapper instance.
+*)
+let get_wrapper (mtype:module_type) : type_wrapper =
+	match mtype with
+		| TClassDecl cls -> get_class_wrapper cls
+		| TEnumDecl enm -> get_enum_wrapper enm
+		| TTypeDecl typedef -> get_typedef_wrapper typedef
+		| TAbstractDecl abstr -> get_abstract_wrapper abstr
+
+(**
+	Drop cached instances of type_wrapper
+*)
+let clear_wrappers () =
+	Hashtbl.clear classes;
+	Hashtbl.clear enums;
+	Hashtbl.clear typedefs;
+	Hashtbl.clear abstracts
+
+(**
+	Check if specified type name is used in specified namespace
+*)
+let namespaces_types_cache = Hashtbl.create 512
+let type_name_used_in_namespace ctx name namespace =
+	let types = Hashtbl.find_all namespaces_types_cache namespace in
+	match types with
+		| [] ->
+			List.iter
+				(fun ctx_type ->
+					let wrapper = get_wrapper ctx_type in
+					Hashtbl.add namespaces_types_cache wrapper#get_namespace wrapper#get_name
+				)
+				ctx.types;
+			let types = Hashtbl.find_all namespaces_types_cache namespace in
+			List.mem name types
+		| _ ->
+			List.mem name types
+
+(**
+	Class to simplify collecting lists of declared and used local vars.
+	Collected data is needed to generate closures correctly.
+*)
+class local_vars =
+	object (self)
+		(** Hashtbl to collect local var used in current scope *)
+		val mutable used_locals = [Hashtbl.create 100]
+		(** Hashtbl to collect local vars declared in current scope *)
+		val mutable declared_locals = [Hashtbl.create 100]
+		(**
+			Clear collected data
+		*)
+		method clear : unit =
+			used_locals <- [Hashtbl.create 100];
+			declared_locals <- [Hashtbl.create 100]
+		(**
+			This method should be called upone entering deeper scope.
+			E.g. right before processing a closure. Just before closure arguments handling.
+		*)
+		method dive : unit =
+			used_locals <- (Hashtbl.create 100) :: used_locals;
+			declared_locals <- (Hashtbl.create 100) :: declared_locals
+		(**
+			This method should be called right after leaving a scope.
+			@return List of vars names used in finished scope, but declared in higher scopes.
+					And list of vars names declared in finished scope.
+		*)
+		method pop : string list * string list =
+			match used_locals with
+				| [] -> assert false
+				| used :: rest_used ->
+					match declared_locals with
+						| [] -> assert false
+						| declared :: rest_declared ->
+							let higher_vars = diff_lists (hashtbl_keys used) (hashtbl_keys declared)
+							and declared_vars = hashtbl_keys declared in
+							used_locals <- rest_used;
+							declared_locals <- rest_declared;
+							List.iter self#used higher_vars;
+							(higher_vars, declared_vars)
+		(**
+			This method should be called right after leaving a scope.
+			@return List of vars names used in finished scope, but declared in higher scopes
+		*)
+		method pop_used : string list = match self#pop with (higher_vars, _) -> higher_vars
+		(**
+			This method should be called right after leaving a scope.
+			@return List of vars names declared in finished scope
+		*)
+		method pop_declared : string list = match self#pop with (_, declared_vars) -> declared_vars
+		(**
+			Specify local var name declared in current scope
+		*)
+		method declared (name:string) : unit =
+			match declared_locals with
+				| [] -> assert false
+				| current :: _ -> Hashtbl.replace current name name
+		(**
+			Specify local var name used in current scope
+		*)
+		method used (name:string) : unit =
+			match used_locals with
+				| [] -> assert false
+				| current :: _ -> Hashtbl.replace current name name
+	end
+
+(**
+	Base class for type builders
+*)
+class virtual type_builder ctx wrapper =
+	object (self)
+		(** This is required to make wrapper accessible by extending classes *)
+		val wrapper = wrapper
+		(** This is required to make conext accessible by extending classes *)
+		val ctx = ctx
+		(** List of types for "use" section *)
+		val use_table = Hashtbl.create 50
+		(** Output buffer *)
+		val mutable buffer = Buffer.create 1024
+		(** Cache for generated conent *)
+		val mutable contents = ""
+		(** Intendation used for each line written *)
+		val mutable indentation = ""
+		(** Expressions nesting. E.g. "if(callFn(ident))" will be represented as [ident, callFn, if] *)
+		val mutable expr_hierarchy : texpr list = []
+		(** Object to collect local vars declarations and usage as we iterate through methods' expressions *)
+		val vars = new local_vars
+		(**
+			Get PHP namespace path
+		*)
+		method get_namespace =
+			match get_php_prefix ctx with
+				| [] -> get_real_path wrapper#get_namespace
+				| prefix -> get_real_path (prefix @ wrapper#get_namespace)
+		(**
+			Get type name
+		*)
+		method get_name : string = get_real_name wrapper#get_name
+		(**
+			Get full type path
+		*)
+		method get_type_path : path =
+			match wrapper#get_type_path with
+				| (path, name) -> (get_real_path path, get_real_name name)
+		(**
+			Returns hx source file name where this type was declared
+		*)
+		method get_source_file : string = wrapper#get_source_file
+		(**
+			Writes type declaration line to output buffer.
+			E.g. "class SomeClass extends Another implements IFace"
+		*)
+		method virtual private write_declaration : unit
+		(**
+			Writes type body to output buffer.
+			E.g. for "class SomeClass { <BODY> }" writes <BODY> part.
+		*)
+		method virtual private write_body : unit
+		(**
+			Writes expressions for `__hx__init` method
+		*)
+		method virtual private write_hx_init_body : unit
+		(**
+			Writes additional initialization code, which should be called before `__hx__init()`
+		*)
+		method virtual private write_pre_hx_init : unit
+		(**
+			Writes initialization code for type instances
+		*)
+		method virtual private write_instance_initialization : unit
+		(**
+			Indicates if type should be declared as `final`
+		*)
+		method is_final = false
+		(**
+			Indicates if `field` should be declared as `final`
+		*)
+		method is_final_field (field:tclass_field) : bool = false
+		(**
+			Increase indentation by one level
+		*)
+		method indent_more =
+			indentation <- indentation ^ "\t";
+		(**
+			Decrease indentation by one level
+		*)
+		method indent_less =
+			indentation <- String.make ((String.length indentation) - 1) '\t';
+		(**
+			Set indentation level (starting from zero for no indentation)
+		*)
+		method indent level =
+			indentation <- String.make level '\t';
+		(**
+			Indicates if class has user-defined static __init__ method
+			@see http://old.haxe.org/doc/advanced/magic#initialization-magic
+		*)
+		method has_magic_init = match wrapper#get_magic_init with None -> false | Some _ -> true
+		(**
+			Returns generated file contents
+		*)
+		method get_contents =
+			if (String.length contents) = 0 then begin
+				self#write_declaration;
+				self#indent 0;
+				self#write_line "{"; (** opening bracket for a class *)
+				self#write_body;
+				if wrapper#needs_initialization then self#write_hx_init;
+				self#indent 0;
+				self#write_line "}"; (** closing bracket for a class *)
+				self#write_empty_lines;
+				let boot_class = self#use boot_type_path in
+				(* Boot initialization *)
+				if boot_type_path = self#get_type_path then
+					self#write_statement (boot_class ^ "::__hx__init()");
+				(*let php_class = get_full_type_name ~escape:true ~omit_first_slash:true (add_php_prefix ctx self#get_type_path)*)
+				let haxe_class = match wrapper#get_type_path with (path, name) -> String.concat "." (path @ [name]) in
+				self#write_statement (boot_class ^ "::registerClass(" ^ (self#get_name) ^ "::class, '" ^ haxe_class ^ "')");
+				self#write_rtti_meta;
+				self#write_pre_hx_init;
+				(* Current class initialization *)
+				if wrapper#needs_initialization && boot_type_path <> self#get_type_path then
+					self#write_statement (self#get_name ^ "::__hx__init()");
+				let body = Buffer.contents buffer in
+				Buffer.clear buffer;
+				self#write_header;
+				self#write "\n";
+				let header = Buffer.contents buffer in
+				contents <- header ^ body;
+			end;
+			contents
+		(**
+			Adds type to "use" section if not added yet.
+			If it's a top-level type then type name returned without adding to "use" section.
+			@return Unique alias for specified type.
+		*)
+		method use ?prefix (type_path:path) =
+			if type_path = wrapper#get_type_path then
+				self#get_name
+			else
+				let type_path = match type_path with (pack, name) -> (pack, get_real_name name) in
+				let type_path =
+					match prefix with
+						| Some false -> type_path
+						| _ -> add_php_prefix ctx type_path
+				in
+				let module_path = get_module_path type_path in
+				match type_path with
+					| ([], type_name) -> "\\" ^ type_name
+					| _ ->
+						let alias_source = ref (List.rev module_path) in
+						let get_alias_next_part () =
+							match !alias_source with
+								| [] ->  failwith ("Failed to find already used type: " ^ get_full_type_name type_path)
+								| name :: rest ->
+									alias_source := rest;
+									String.capitalize name
+						and added = ref false
+						and alias = ref (get_type_name type_path) in
+						if !alias = self#get_name then
+							alias := get_alias_next_part () ^ !alias;
+						while not !added do
+							try
+								if (get_module_path type_path) <> wrapper#get_namespace && type_name_used_in_namespace ctx !alias wrapper#get_namespace then
+									alias := get_alias_next_part () ^ !alias
+								else
+									let used_type = Hashtbl.find use_table !alias in
+									if used_type = type_path then
+										added := true
+									else
+										alias := get_alias_next_part () ^ !alias;
+							with
+								| Not_found ->
+									Hashtbl.add use_table !alias type_path;
+									added := true
+								| _ -> fail self#pos __POS__
+						done;
+						!alias
+		(**
+			Extracts type path from Type.t value and execute self#use on it
+			@return Unique alias for specified type.
+		*)
+		method use_t (t_inst:Type.t) =
+			match follow t_inst with
+				| TEnum (tenum, _) -> self#use tenum.e_path
+				| TInst (tcls, _) ->
+					(match tcls.cl_kind with
+						| KTypeParameter _ -> "mixed"
+						| _ ->
+							(match tcls.cl_path with
+								| ([], "String") -> "string"
+								| _ -> self#use ~prefix:(not tcls.cl_extern) tcls.cl_path
+							)
+					)
+				| TFun _ -> self#use ~prefix:false ([], "Closure")
+				| TAnon _ -> "object"
+				| TDynamic _ -> "mixed"
+				| TLazy _ -> failwith "TLazy not implemented"
+				| TMono mono ->
+					(match !mono with
+						| None -> "mixed"
+						| Some t -> self#use_t t
+					)
+				| TType _ -> failwith "TType not implemented"
+				| TAbstract (abstr, _) ->
+					match abstr.a_path with
+						| ([],"Int") -> "int"
+						| ([],"Float") -> "float"
+						| ([],"Bool") -> "bool"
+						| ([],"Void") -> "void"
+						| ([],"Enum") -> "Enum"
+						| ([], "Class") -> "Class"
+						| _ when Meta.has Meta.CoreType abstr.a_meta -> "mixed"
+						| _ -> self#use_t abstr.a_this
+		(**
+			Indicates whether current expression nesting level is a top level of a block
+		*)
+		method private parent_expr_is_block =
+			let rec expr_is_block expr parents =
+				match expr.eexpr with
+					| TBlock _ -> true
+					| TIf (_, if_expr, Some else_expr) ->
+						if (expr_is_block if_expr []) || (expr_is_block else_expr []) then
+							true
+						else
+							(match parents with
+								| parent :: rest -> expr_is_block parent rest
+								| [] -> false
+							)
+					| TIf (_, _, None) -> true
+					| TTry _ -> true
+					| TWhile _ -> true
+					| TSwitch _ -> true
+					| _ -> false
+			in
+			match expr_hierarchy with
+				| _ :: parent :: rest -> expr_is_block parent rest
+				| _ -> false
+		(**
+			Returns parent expression.
+		*)
+		method private parent_expr =
+			match expr_hierarchy with
+				| _ :: expr :: _ -> Some expr
+				| _ -> None
+		(**
+			Indicates if parent expression is a call (bypasses casts and metas)
+		*)
+		method private parent_expr_is_call =
+			let rec expr_is_call expr parents =
+				match expr.eexpr with
+					| TCast _
+					| TMeta _ ->
+						(match parents with
+							| parent :: rest -> expr_is_call parent rest
+							| [] -> false
+						)
+					| TCall _ -> true
+					| _ -> false
+			in
+			match expr_hierarchy with
+				| _ :: parent :: rest -> expr_is_call parent rest
+				| _ -> false
+		(**
+			Position of currently generated code in source hx files
+		*)
+		method private pos =
+			match expr_hierarchy with
+				| { epos = pos } :: _ -> pos
+				| _ -> dummy_pos
+		(**
+			Add a function call to "dereference" part of expression to avoid "Cannot use temporary expression in write context"
+			erro in expressions like:
+			```
+			new MyClass().fieldName = 'value';
+			```
+		*)
+		method private dereference expr =
+			let boot_cls = get_boot ctx in
+			let deref_field = PMap.find "deref" boot_cls.cl_statics in
+			match expr.eexpr with
+				| TField (target_expr, access) ->
+					{
+						expr with eexpr = TField (
+							{
+								target_expr with eexpr = TCall (
+									{
+										target_expr with eexpr = TField (
+											{
+												target_expr with eexpr = TTypeExpr (TClassDecl boot_cls)
+											},
+											FStatic (boot_cls, deref_field)
+										)
+									},
+									[ target_expr ]
+								)
+							},
+							access
+						)
+					}
+				| TArray (target_expr, access_expr) ->
+					{
+						expr with eexpr = TArray (
+							{
+								target_expr with eexpr = TCall (
+									{
+										target_expr with eexpr = TField (
+											{
+												target_expr with eexpr = TTypeExpr (TClassDecl boot_cls)
+											},
+											FStatic (boot_cls, deref_field)
+										)
+									},
+									[ target_expr ]
+								)
+							},
+							access_expr
+						)
+					}
+				| _ -> fail self#pos __POS__
+		(**
+			Writes specified string to output buffer
+		*)
+		method private write str =
+			Buffer.add_string buffer str
+		(**
+			Writes fixed amount of empty lines (E.g. between methods)
+		*)
+		method private write_empty_lines =
+			self#write "\n";
+			self#write "\n"
+		(**
+			Writes current indentation to output buffer
+		*)
+		method private write_indentation =
+			Buffer.add_string buffer indentation
+		(**
+			Writes specified line to output buffer and appends \n
+		*)
+		method private write_line line =
+			Buffer.add_string buffer (indentation ^ line ^ "\n")
+		(**
+			Writes specified statement to output buffer and appends ";\n"
+		*)
+		method private write_statement statement =
+			Buffer.add_string buffer (indentation ^ statement ^ ";\n")
+		(**
+			Build file header (<?php, namespace and file doc block)
+		*)
+		method private write_header =
+			self#indent 0;
+			self#write_line "<?php";
+			let namespace = self#get_namespace in
+			if List.length namespace > 0 then
+				self#write_line ("namespace " ^ (String.concat "\\" namespace) ^ ";\n");
+			self#write_use
+		(**
+			Build "use" statements
+		*)
+		method private write_use =
+			self#indent 0;
+			let write alias type_path =
+				if (get_module_path type_path) <> wrapper#get_namespace then
+					if get_type_name type_path = alias then
+						self#write_statement ("use " ^ (get_full_type_name type_path))
+					else
+						let full_name = get_full_type_name type_path in
+						self#write_statement ("use " ^ full_name ^ " as " ^ alias)
+			in
+			Hashtbl.iter write use_table
+		(**
+			Writes array item declaration to output buffer and appends ",\n"
+		*)
+		method private write_array_item ?key value_expr =
+			(match key with
+				| None ->
+					self#write_indentation;
+					self#write_expr value_expr;
+				| Some key_str ->
+					self#write (indentation  ^ "\"" ^ (String.escaped key_str) ^ "\" => ");
+					self#write_expr value_expr
+			);
+			self#write ",\n"
+		(**
+			Generates PHP docblock to output buffer.
+		*)
+		method private write_doc doc_block =
+			match doc_block with
+				| DocVar (type_name, doc) ->
+					self#write_line "/**";
+					self#write_line (" * @var " ^ type_name);
+					(match doc with
+						| None -> ()
+						| Some txt -> self#write_doc_description txt
+					);
+					self#write_line " */"
+				| DocClass doc ->
+					(match doc with
+						| None -> ()
+						| Some txt ->
+							self#write_line "/**";
+							self#write_doc_description txt;
+							self#write_line " */"
+					)
+				| DocMethod (args, return, doc) ->
+					self#write_method_docblock args return doc
+		(**
+			Writes description section of docblocks
+		*)
+		method write_doc_description (doc:string) =
+			let lines = Str.split (Str.regexp "\n") (String.trim doc)
+			and write_line line =
+				let trimmed = String.trim line in
+				if String.length trimmed > 0 then (
+					if String.get trimmed 0 = '*' then
+						self#write_line (" " ^ trimmed)
+					else
+						self#write_line (" * " ^ trimmed)
+				)
+			in
+			List.iter write_line lines
+		(**
+			Generates docblock for a method and writes it to output buffer
+		*)
+		method write_method_docblock args return_type doc =
+			self#write_line "/**";
+			(match doc with
+				| None -> ()
+				| Some txt ->
+					self#write_doc_description txt;
+					self#write_line " * "
+			);
+			let write_arg arg =
+				match arg with
+					| (arg_name, is_optional, arg_type) ->
+						self#write_line (" * @param " ^ (self#use_t arg_type) ^ " $" ^ arg_name)
+			in
+			List.iter write_arg args;
+			if List.length args > 0 then self#write_line " * ";
+			self#write_line (" * @return " ^ (self#use_t return_type));
+			self#write_line " */"
+		(**
+			Writes rtti meta to output buffer
+		*)
+		method write_rtti_meta =
+			match Codegen.build_metadata ctx wrapper#get_module_type with
+				| None -> ()
+				| Some meta_expr ->
+					let boot_class = self#use boot_type_path in
+					self#write (boot_class ^ "::registerMeta(" ^ (self#get_name) ^ "::class, ");
+					self#write_expr meta_expr;
+					self#write ");\n"
+		(**
+			Writes expression to output buffer
+		*)
+		method private write_expr (expr:texpr) =
+			expr_hierarchy <- expr :: expr_hierarchy;
+			(match expr.eexpr with
+				| TConst const -> self#write_expr_const const
+				| TLocal var ->
+					vars#used var.v_name;
+					self#write ("$" ^ var.v_name)
+				| TArray (target, index) -> self#write_expr_array_access target index
+				| TBinop (operation, expr1, expr2) when needs_dereferencing expr1 ->
+					self#write_expr { expr with eexpr = TBinop (operation, self#dereference expr1, expr2) }
+				| TBinop (operation, expr1, expr2) -> self#write_expr_binop operation expr1 expr2
+				| TField (fexpr, access) when is_php_global expr -> self#write_expr_php_global expr
+				| TField (fexpr, access) when is_php_class_const expr -> self#write_expr_php_class_const expr
+				| TField (expr, access) -> self#write_expr_field expr access
+				| TTypeExpr mtype -> self#write_expr_type mtype
+				| TParenthesis expr ->
+					self#write "(";
+					self#write_expr expr;
+					self#write ")"
+				| TObjectDecl fields -> self#write_expr_object_declaration fields
+				| TArrayDecl exprs -> self#write_expr_array_decl exprs
+				| TCall ({ eexpr = TLocal { v_name = name }}, args) when is_magic expr -> self#write_expr_magic name args
+				| TCall ({ eexpr = TField (expr, access) }, args) when is_string expr -> self#write_expr_call_string expr access args
+				| TCall (expr, args) when is_lang_extern expr -> self#write_expr_call_lang_extern expr args
+				| TCall (target, args) when is_sure_var_field_access target -> self#write_expr_call (parenthesis target) args
+				| TCall (target, args) -> self#write_expr_call target args
+				| TNew (_, _, args) when is_string expr -> write_args buffer self#write_expr args
+				| TNew (tcls, _, args) -> self#write_expr_new tcls args
+				| TUnop (operation, flag, target_expr) when needs_dereferencing target_expr ->
+					self#write_expr { expr with eexpr = TUnop (operation, flag, self#dereference target_expr) }
+				| TUnop (operation, flag, expr) -> self#write_expr_unop operation flag expr
+				| TFunction fn -> self#write_expr_function fn
+				| TVar (var, expr) -> self#write_expr_var var expr
+				| TBlock exprs -> self#write_expr_block expr
+				| TFor (var, iterator, body) -> fail self#pos __POS__
+				| TIf (condition, if_expr, else_expr) -> self#write_expr_if condition if_expr else_expr
+				| TWhile (condition, expr, do_while) -> self#write_expr_while condition expr do_while
+				| TSwitch (switch, cases, default ) -> self#write_expr_switch switch cases default
+				| TTry (try_expr, catches) -> self#write_expr_try_catch try_expr catches
+				| TReturn expr -> self#write_expr_return expr
+				| TBreak -> self#write_expr_loop_flow "break"
+				| TContinue -> self#write_expr_loop_flow "continue"
+				| TThrow expr -> self#write_expr_throw expr
+				| TCast (expr, mtype) -> self#write_expr_cast expr mtype
+				| TMeta (_, expr) -> self#write_expr expr
+				| TEnumParameter (expr, constructor, index) -> self#write_expr_enum_parameter expr constructor index
+			);
+			expr_hierarchy <- List.tl expr_hierarchy
+		(**
+			Writes type initialization method.
+		*)
+		method private write_hx_init =
+			self#write_empty_lines;
+			self#indent 1;
+			self#write_line "/**";
+			self#write_line " * @internal";
+			self#write_line " * @access private";
+			self#write_line " */";
+			self#write_line "static public function __hx__init ()";
+			self#write_line "{";
+			self#indent_more;
+			self#write_statement "static $called = false";
+			self#write_statement "if ($called) return";
+			self#write_statement "$called = true";
+			self#write "\n";
+			vars#clear;
+			(match wrapper#get_magic_init with
+				| None -> ()
+				| Some expr -> self#write_fake_block expr
+			);
+			self#write "\n";
+			vars#clear;
+			self#write_hx_init_body;
+			self#indent 1;
+			self#write_line "}"
+		(**
+			Writes `continue N` or `break N` with required N depending on nearest parent loop and amount of `switch` between loop and
+			`continue/break`
+		*)
+		method private write_expr_loop_flow word =
+			let rec count_N parent_exprs count =
+				match parent_exprs with
+					| [] -> count
+					| { eexpr = TWhile _ } :: _ -> count
+					| { eexpr = TSwitch _ } :: rest -> count_N rest (count + 1)
+					| _ :: rest -> count_N rest count
+			in
+			let count = count_N expr_hierarchy 1 in
+			if count > 1 then
+				self#write (word ^ " " ^ (string_of_int count))
+			else
+				self#write word
+		(**
+			Writes TConst to output buffer
+		*)
+		method private write_expr_const const =
+			match const with
+				| TInt value -> self#write (Int32.to_string value)
+				| TFloat str -> self#write str
+				| TString str -> self#write ("\"" ^ (escape_bin str) ^ "\"")
+				| TBool value -> self#write (if value then "true" else "false")
+				| TNull -> self#write "null"
+				| TThis -> self#write "$this"
+				| TSuper -> self#write "parent"
+		(**
+			Writes TArrayDecl to output buffer
+		*)
+		method private write_expr_array_decl exprs =
+			match exprs with
+				| [] -> self#write ("new " ^ (self#use array_type_path) ^ "()")
+				| [expr] ->
+					self#write ((self#use array_type_path) ^ "::wrap([");
+					self#write_expr expr;
+					self#write "])"
+				| _ ->
+					self#write ((self#use array_type_path) ^ "::wrap([\n");
+					self#indent_more;
+					List.iter (fun expr -> self#write_array_item expr) exprs;
+					self#indent_less;
+					self#write_indentation;
+					self#write "])"
+		(**
+			Writes TArray to output buffer
+		*)
+		method private write_expr_array_access target index =
+			(*self#write_expr target;
+			self#write "[";
+			self#write_expr index;
+			self#write "]"*)
+			let write_index left_bracket right_bracket =
+				self#write left_bracket;
+				self#write_expr index;
+				self#write right_bracket
+			in
+			match follow target.etype with
+				| TInst ({ cl_path = path }, _) when path = array_type_path ->
+					(match self#parent_expr with
+						| Some { eexpr = TBinop (OpAssign, { eexpr = TArray (t, i) }, _) } when t == target ->
+							self#write_expr target;
+							write_index "[" "]"
+						| Some { eexpr = TBinop (OpAssignOp _, { eexpr = TArray (t, i) }, _) } when t == target ->
+							self#write_expr target;
+							write_index "[" "]"
+						| Some { eexpr = TUnop (op, _, { eexpr = TArray (t, i) }) } when t == target && is_modifying_unop op ->
+							self#write_expr target;
+							write_index "[" "]"
+						| Some { eexpr = TField ({ eexpr = TArray (t, i) }, _) } ->
+							self#write_expr target;
+							write_index "[" "]"
+						| _ ->
+							self#write "(";
+							self#write_expr target;
+							self#write "->arr";
+							write_index "[" "] ?? null)"
+					)
+				| _ ->
+					self#write_expr target;
+					write_index "[" "]"
+		(**
+			Writes TVar to output buffer
+		*)
+		method private write_expr_var var expr =
+			vars#declared var.v_name;
+			self#write ("$" ^ var.v_name ^ " = ");
+			match expr with
+				| None -> self#write "null"
+				| Some expr -> self#write_expr expr
+		(**
+			Writes TFunction to output buffer
+		*)
+		method private write_expr_function ?name func =
+			match name with
+				| None -> self#write_closure_declaration func self#write_function_arg
+				| Some "__construct" -> self#write_constructor_function_declaration func self#write_function_arg
+				| Some name -> self#write_method_function_declaration name func self#write_function_arg
+		(**
+			Writes constructor declaration (except visibility and `static` keywords) to output buffer
+		*)
+		method private write_constructor_function_declaration func write_arg =
+			self#write ("function __construct (");
+			write_args buffer write_arg func.tf_args;
+			self#write ")";
+			self#indent 1;
+			self#write "\n";
+			self#write_line "{";
+			self#indent_more;
+			self#write_instance_initialization;
+			self#write_fake_block (inject_defaults ctx func);
+			self#indent_less;
+			self#write_indentation;
+			self#write "}"
+		(**
+			Writes method declaration (except visibility and `static` keywords) to output buffer
+		*)
+		method private write_method_function_declaration name func write_arg =
+			let by_ref = if is_ref func.tf_type then "&" else "" in
+			self#write ("function " ^ by_ref ^ name ^ " (");
+			write_args buffer write_arg func.tf_args;
+			self#write ")";
+			self#indent 1;
+			self#write "\n";
+			self#write_indentation;
+			self#write_expr (inject_defaults ctx func)
+		(**
+			Writes closure declaration to output buffer
+		*)
+		method private write_closure_declaration func write_arg =
+			vars#dive;
+			self#write "function (";
+			write_args buffer write_arg func.tf_args;
+			self#write ")";
+			(* Generate closure body to separate buffer *)
+			let original_buffer = buffer in
+			buffer <- Buffer.create 256;
+			self#write_expr (inject_defaults ctx func);
+			let body = Buffer.contents buffer in
+			buffer <- original_buffer;
+			(* Use captured local vars *)
+			let used_vars = vars#pop_used in
+			self#write " ";
+			if List.length used_vars > 0 then begin
+				self#write " use (";
+				write_args buffer (fun name -> self#write ("&$" ^ name)) used_vars;
+				self#write ") "
+			end;
+			self#write body
+		(**
+			Writes TBlock to output buffer
+		*)
+		method private write_expr_block block_expr =
+			(* Check if parent expr could not contain blocks in PHP, adn this block needs to be wrapped in a closure. *)
+			let needs_closure = match self#parent_expr with
+				| None -> false
+				| Some e ->
+					match e.eexpr with
+						| TIf (_, _, _) -> false
+						| TWhile (_, _, _) -> false
+						| TTry (_, _) -> false
+						| TFor (_, _, _) -> false
+						| TFunction _ -> false
+						| TBlock _ -> false
+						| TSwitch (_, _, _) -> false
+						| _ -> true
+			in
+			if needs_closure then
+				begin
+					self#write "(";
+					self#write_expr {
+						block_expr with eexpr = TFunction {
+							tf_args = [];
+							tf_type = block_expr.etype;
+							tf_expr = ensure_return_in_block block_expr;
+						}
+					};
+					self#write ")()"
+				end
+			else
+				begin
+					let inline_block = self#parent_expr_is_block in
+					self#write_as_block ~inline:inline_block block_expr
+				end
+		(**
+			Emulates TBlock for parent expression and writes `expr` as inlined block
+		*)
+		method private write_fake_block expr =
+			self#write_indentation;
+			let fake_block = { expr with eexpr = TBlock [expr] } in
+			expr_hierarchy <- fake_block :: expr_hierarchy;
+			self#write_as_block ~inline:true expr;
+			expr_hierarchy <- List.tl expr_hierarchy
+		(**
+			Writes "{ <expressions> }" to output buffer
+		*)
+		method private write_as_block ?inline ?unset_locals expr =
+			let unset_locals = match unset_locals with Some true -> true | _ -> false
+			and exprs = match expr.eexpr with TBlock exprs -> exprs | _ -> [expr] in
+			let write_body () =
+				let write_expr expr =
+					self#write_expr expr;
+					match expr.eexpr with
+						| TBlock _ | TIf _ | TTry _ | TSwitch _ | TWhile (_, _, NormalWhile) -> self#write "\n"
+						| _ -> self#write ";\n"
+				in
+				let write_expr_with_indent expr =
+					self#write_indentation;
+					write_expr expr
+				in
+				let write_exprs () =
+					match exprs with
+						| [] -> ()
+						| first :: rest ->
+							write_expr first; (* write first expression without indentation in case of block inlining *)
+							List.iter write_expr_with_indent rest
+				in
+				if unset_locals then
+					begin
+						let original_buffer = buffer in
+						buffer <- Buffer.create 256;
+						vars#dive;
+						write_exprs();
+						let body = Buffer.contents buffer in
+						buffer <- original_buffer;
+						let locals = vars#pop_declared in
+						if List.length locals > 0 then begin
+							self#write ("unset($" ^ (String.concat ", $" locals) ^ ");\n");
+							self#write_indentation
+						end;
+						self#write body
+					end
+				else
+					write_exprs()
+			in
+			match inline with
+				| Some true -> write_body ()
+				| _ ->
+					self#write "{\n";
+					self#indent_more;
+					(match exprs with
+						| [] -> ()
+						| _ ->
+							self#write_indentation; (* indentation for the first expression in block *)
+							write_body ()
+					);
+					self#indent_less;
+					self#write_indentation;
+					self#write "}"
+		(**
+			Writes TReturn to output buffer
+		*)
+		method private write_expr_return expr =
+			match expr with
+				| None -> self#write "return";
+				| Some expr ->
+					self#write "return ";
+					self#write_expr expr
+		(**
+			Writes TThrow to output buffer
+		*)
+		method private write_expr_throw expr =
+			self#write "throw ";
+			if is_native_exception expr.etype then
+				self#write_expr expr
+			else if sure_extends_extern expr.etype || is_dynamic_type expr.etype then
+				begin
+					self#write "(is_object($__hx__throw = ";
+					self#write_expr expr;
+					self#write (") && $__hx__throw instanceof \\Throwable ? $__hx__throw : new " ^ (self#use hxexception_type_path) ^ "($__hx__throw))")
+				end
+			else
+				begin
+					self#write ("new " ^ (self#use hxexception_type_path) ^ "(");
+					self#write_expr expr;
+					self#write ")"
+				end
+		(**
+			Writes try...catch to output buffer
+		*)
+		method private write_expr_try_catch try_expr catches =
+			let catching_dynamic = ref false in
+			let haxe_exception = self#use hxexception_type_path
+			and first_catch = ref true in
+			let write_catch (var, expr) =
+				let dynamic = ref false in
+				(match follow var.v_type with
+					| TInst ({ cl_path = ([], "String") }, _) -> self#write "if (is_string($__hx__real_e)) {\n"
+					| TAbstract ({ a_path = ([], "Float") }, _) -> self#write "if (is_float($__hx__real_e)) {\n"
+					| TAbstract ({ a_path = ([], "Int") }, _) -> self#write "if (is_int($__hx__real_e)) {\n"
+					| TAbstract ({ a_path = ([], "Bool") }, _) -> self#write "if (is_bool($__hx__real_e)) {\n"
+					| TDynamic _ ->
+						dynamic := true;
+						catching_dynamic := true;
+						if not !first_catch then self#write "{\n"
+					| vtype -> self#write ("if ($__hx__real_e instanceof " ^ (self#use_t vtype) ^ ") {\n")
+				);
+				if !dynamic && !first_catch then
+					begin
+						self#write ("$" ^ var.v_name ^ " = $__hx__real_e;\n");
+						self#write_indentation;
+						self#write_as_block ~inline:true expr;
+					end
+				else
+					begin
+						self#indent_more;
+						self#write_statement ("$" ^ var.v_name ^ " = $__hx__real_e");
+						self#write_indentation;
+						self#write_as_block ~inline:true expr;
+						self#indent_less;
+						self#write_indentation;
+						self#write "}";
+					end;
+				if not !dynamic then self#write " else ";
+				first_catch := false;
+			in
+			self#write "try ";
+			self#write_as_block try_expr;
+			self#write " catch (\\Throwable $__hx__caught_e) {\n";
+			self#indent_more;
+			if ctx.debug then
+				self#write_statement ((self#use (["haxe"], "CallStack")) ^ "::saveExceptionTrace($__hx__caught_e)");
+			self#write_statement ("$__hx__real_e = ($__hx__caught_e instanceof " ^ haxe_exception ^ " ? $__hx__caught_e->e : $__hx__caught_e)");
+			self#write_indentation;
+			List.iter write_catch catches;
+			if not !catching_dynamic then
+				self#write " throw $__hx__caught_e;\n"
+			else
+				(match catches with [_] -> () | _ -> self#write "\n");
+			self#indent_less;
+			self#write_indentation;
+			self#write "}"
+		(**
+			Writes TCast to output buffer
+		*)
+		method private write_expr_cast expr (mtype:module_type option) =
+			match mtype with
+				| None -> self#write_expr expr
+				| Some mtype ->
+					self#write ((self#use boot_type_path) ^ "::typedCast(");
+					self#write_expr_type mtype;
+					self#write ", ";
+					self#write_expr expr;
+					self#write ")"
+		(**
+			Write Haxe->PHP magic function call
+			@see http://old.haxe.org/doc/advanced/magic#php-magic
+		*)
+		method private write_expr_magic name args =
+			let error = error_message self#pos ("Invalid arguments for " ^ name ^ " magic call") in
+			match args with
+				| [] -> failwith error
+				| { eexpr = TConst (TString code) } as expr :: args ->
+					(match name with
+						| "__php__" ->
+							(match expr.eexpr with
+								| TConst (TString php) ->
+									Codegen.interpolate_code ctx php args self#write self#write_expr self#pos
+								| _ -> fail self#pos __POS__
+							)
+						| "__call__" ->
+							self#write (code ^ "(");
+							write_args buffer self#write_expr args;
+							self#write ")"
+						| "__physeq__" ->
+							(match args with
+								| [expr2] -> self#write_expr_binop OpEq expr expr2
+								| _ -> failwith error
+							)
+						| "__var__" ->
+							(match args with
+								| [expr2] ->
+									self#write ("$" ^ code ^ "[");
+									self#write_expr expr2;
+									self#write "]"
+								| _ -> failwith error
+							)
+						| _ -> failwith error
+					)
+				| [expr1; expr2] ->
+					(match name with
+						| "__physeq__" ->
+							(match args with
+								| [expr1; expr2] -> self#write_expr_binop OpEq expr1 expr2
+								| _ -> failwith error
+							)
+						| _ -> failwith error
+					)
+				| _ -> failwith error
+		(**
+			Writes TTypeExpr to output buffer
+		*)
+		method private write_expr_type (mtype:module_type) =
+			let ttype = type_of_module_type mtype in
+			match expr_hierarchy with
+				| _ :: { eexpr = TField _ } :: _ -> self#write (self#use_t ttype)
+				| _ ->
+					let class_name =
+						match self#use_t ttype with
+							| "int" -> "'Int'"
+							| "float" -> "'Float'"
+							| "bool" -> "'Bool'"
+							| "string" -> "'String'"
+							| "mixed" -> "'Dynamic'"
+							| "Enum" -> "'Enum'"
+							| "Class" -> "'Class'"
+							| name -> name ^ "::class"
+					in
+					self#write ((self#use boot_type_path) ^ "::getClass(" ^ class_name ^ ")")
+		(**
+			Writes binary operation to output buffer
+		*)
+		method private write_expr_binop operation expr1 expr2 =
+			let write_method method_name =
+				self#write (method_name ^ "(");
+				self#write_expr expr1;
+				self#write ", ";
+				self#write_expr expr2;
+				self#write ")"
+			in
+			let write_for_concat expr =
+				if ((is_constant expr) && not (is_constant_null expr)) || (is_concatenation expr) then
+					self#write_expr expr
+				else begin
+					self#write "(";
+					self#write_expr expr;
+					self#write "??'null')"
+				end
+			and write_binop ?writer ?right_writer str =
+				let write_left = match writer with None -> self#write_expr | Some writer -> writer in
+				let write_right = match right_writer with None -> write_left | Some writer -> writer
+				and need_parenthesis =
+					match expr_hierarchy with
+						| _ :: { eexpr = TBinop (parent, _, _) } :: _ -> need_parenthesis_for_binop operation parent
+						| _ -> false
+				in
+				if need_parenthesis then self#write "(";
+				write_left expr1;
+				self#write str;
+				write_right expr2;
+				if need_parenthesis then self#write ")"
+			and compare_strings op =
+				write_method "strcmp";
+				self#write (op ^ "0")
+			in
+			let compare op =
+				if is_string expr1 && is_string expr2 then
+						compare_strings op
+					else
+						write_binop op
+			in
+			match operation with
+				| OpAdd ->
+					if (is_string expr1) || (is_string expr2) then
+						write_binop ~writer:write_for_concat " . "
+					else if (is_unknown_type expr1.etype) && (is_unknown_type expr2.etype) then
+						write_method ((self#use boot_type_path) ^ "::addOrConcat")
+					else
+						write_binop " + "
+				| OpMult -> write_binop " * "
+				| OpDiv -> write_binop " / "
+				| OpSub -> write_binop " - "
+				| OpAssign -> write_binop " = "
+				| OpEq ->
+					if need_boot_equal expr1 expr2 then
+						write_method ((self#use boot_type_path) ^ "::equal")
+					else
+						write_binop " === "
+				| OpNotEq ->
+					if need_boot_equal expr1 expr2 then
+						begin
+							self#write "!";
+							write_method ((self#use boot_type_path) ^ "::equal")
+						end
+					else
+						write_binop " !== "
+				| OpGt -> compare " > "
+				| OpGte -> compare " >= "
+				| OpLt -> compare " < "
+				| OpLte -> compare " <= "
+				| OpAnd -> write_binop " & "
+				| OpOr -> write_binop " | "
+				| OpXor -> write_binop " ^ "
+				| OpBoolAnd -> write_binop " && "
+				| OpBoolOr -> write_binop " || "
+				| OpShl  -> write_binop " << "
+				| OpShr -> write_binop " >> "
+				| OpMod ->
+					if is_int expr1 && is_int expr2 then
+						write_binop " % "
+					else
+						write_method "fmod"
+				| OpUShr -> write_method ((self#use boot_type_path) ^ "::shiftRightUnsigned")
+				| OpAssignOp OpAdd ->
+					if (is_string expr1) then
+						begin
+							self#write_expr expr1;
+							self#write " = ";
+							write_binop ~writer:write_for_concat " . "
+						end
+					else if (is_unknown_type expr1.etype) && (is_unknown_type expr2.etype) then
+						begin
+							self#write_expr expr1;
+							self#write " = ";
+							write_method ((self#use boot_type_path) ^ "::addOrConcat")
+						end
+					else
+						write_binop " += "
+				| OpAssignOp OpMult -> write_binop " *= "
+				| OpAssignOp OpDiv -> write_binop " /= "
+				| OpAssignOp OpSub -> write_binop " -= "
+				| OpAssignOp OpAnd -> write_binop " &= "
+				| OpAssignOp OpOr -> write_binop " |= "
+				| OpAssignOp OpXor -> write_binop " ^= "
+				| OpAssignOp OpShl  -> write_binop " <<= "
+				| OpAssignOp OpShr -> write_binop " >>= "
+				| OpAssignOp OpMod ->
+					if is_int expr1 && is_int expr2 then
+						write_binop " %= "
+					else
+						write_method "fmod"
+				| OpAssignOp OpUShr ->
+					self#write_expr expr1;
+					self#write " = ";
+					write_method ((self#use boot_type_path) ^ "::shiftRightUnsigned")
+				| _ -> fail self#pos __POS__
+		(**
+			Writes TUnOp to output buffer
+		*)
+		method private write_expr_unop operation flag expr =
+			let write_unop operation =
+				match operation with
+					| Increment -> self#write "++"
+					| Decrement -> self#write "--"
+					| Not -> self#write "!"
+					| Neg -> self#write "-"
+					| NegBits -> self#write "~"
+			in
+			match flag with
+				| Prefix ->
+					write_unop operation;
+					self#write_expr expr
+				| Postfix ->
+					self#write_expr expr;
+					write_unop operation
+		(**
+			Writes TField to output buffer
+		*)
+		method private write_expr_field expr access =
+			let write_access access_str field_str =
+				let access_str = ref access_str in
+				let expr_without_casts = reveal_expr expr in
+				(match expr_without_casts.eexpr with
+					| TNew _
+					| TArrayDecl _
+					| TObjectDecl _ -> self#write_expr (parenthesis expr)
+					| TConst TSuper ->
+						self#write "parent";
+						access_str := "::"
+					| _ -> self#write_expr expr
+				);
+				self#write (!access_str ^ field_str)
+			in
+			match (follow expr.etype, access) with
+				| (TInst ({ cl_path = ([], "String") }, _), FInstance (_, _, { cf_name = "length"; cf_kind = Var _ })) ->
+					self#write "strlen(";
+					self#write_expr expr;
+					self#write ")"
+				| (_, FInstance (_, _, field)) -> write_access "->" (field_name field)
+				| (_, FStatic (_, ({ cf_kind = Var _ } as field))) ->
+					(match (reveal_expr expr).eexpr with
+						| TTypeExpr _ -> write_access "::" ("$" ^ (field_name field))
+						| _ -> write_access "->" (field_name field)
+					)
+				| (_, FStatic (_, ({ cf_kind = Method MethDynamic } as field))) ->
+					(match expr_hierarchy with
+						| _ :: { eexpr = TCall ({ eexpr = TField (e, a) }, _) } :: _ when a == access ->
+							self#write "(";
+							write_access "::" ("$" ^ (field_name field));
+							self#write ")"
+						| _ ->
+							write_access "::" ("$" ^ (field_name field))
+					)
+				| (_, FStatic (_, ({ cf_kind = Method _ } as field))) -> self#write_expr_field_static expr field
+				| (_, FAnon field) ->
+					let written_as_probable_string = self#write_expr_field_if_string expr (field_name field) in
+					if not written_as_probable_string then write_access "->" (field_name field)
+				| (_, FDynamic field_name) ->
+					let written_as_probable_string = self#write_expr_field_if_string expr field_name in
+					if not written_as_probable_string then write_access "->" field_name
+				| (_, FClosure (tcls, field)) -> self#write_expr_field_closure tcls field expr
+				| (_, FEnum (_, field)) ->
+					if is_enum_constructor_with_args field then
+						if not self#parent_expr_is_call then
+							begin
+								self#write (self#use boot_type_path ^ "::closure(");
+								self#write_expr expr;
+								(match (reveal_expr expr).eexpr with
+									| TTypeExpr _ -> self#write "::class"
+									| _ -> self#write "->phpClassName"
+								);
+								self#write (", '" ^ field.ef_name ^ "')")
+							end
+						else
+							write_access "::" field.ef_name
+					else
+						begin
+							write_access "::" field.ef_name;
+							self#write "()"
+						end
+
+		(**
+			Writes field access on Dynamic expression to output buffer
+		*)
+		method private write_expr_field_if_string expr field_name =
+			(* Special case for String fields *)
+			match field_name with
+				| "length"
+				| "toUpperCase"
+				| "toLowerCase"
+				| "charAt"
+				| "indexOf"
+				| "lastIndexOf"
+				| "split"
+				| "toString"
+				| "substring"
+				| "substr"
+				| "charCodeAt" ->
+					self#write ((self#use hxdynamicstr_type_path) ^ "::wrap(");
+					self#write_expr expr;
+					self#write (")->" ^ field_name);
+					true
+				| _ ->
+					false
+		(**
+			Convert field access expressions for strings to native PHP string functions and write to output buffer
+		*)
+		method private write_expr_call_string expr access args =
+			match access with
+				| FInstance (_, _, ({ cf_kind = Method _ } as field)) ->
+					self#write ((self#use hxstring_type_path) ^ "::" ^ (field_name field) ^ "(");
+					write_args buffer self#write_expr (expr :: args);
+					self#write ")"
+				| _ -> fail self#pos __POS__
+		(**
+			Writes FStatic field access for methods to output buffer
+		*)
+		method private write_expr_field_static expr field =
+			let write_expr () =
+				match expr.eexpr with
+					| TTypeExpr (TClassDecl { cl_path = ([], "String") }) -> self#write (self#use hxstring_type_path)
+					| _ -> self#write_expr expr
+			and operator =
+				match (reveal_expr expr).eexpr with
+					| TTypeExpr _ -> "::"
+					| _ -> "->"
+			in
+			match expr_hierarchy with
+				| _ :: { eexpr = TCall ({ eexpr = TField (e, FStatic (_, f)) }, _) } :: _ when e == expr && f == field ->
+					write_expr ();
+					self#write (operator ^ (field_name field))
+				| _ ->
+					let (args, return_type) = get_function_signature field  in
+					self#write "function(";
+					write_args buffer (self#write_arg true) args;
+					self#write ") { return ";
+					write_expr ();
+					self#write (operator ^ (field_name field) ^ "(");
+					write_args buffer (self#write_arg false) args;
+					self#write "); }"
+		(**
+			Writes FClosure field access to output buffer
+		*)
+		method private write_expr_field_closure tcls field expr =
+			let new_closure = "new " ^ (self#use hxclosure_type_path) in
+			match expr.eexpr with
+				| TTypeExpr mtype ->
+					let class_name = self#use_t (type_of_module_type mtype) in
+					self#write (new_closure ^ "(" ^ class_name ^ "::class, '" ^ (field_name field) ^ "')");
+				| _ ->
+					self#write (new_closure ^ "(");
+					(match follow expr.etype with
+						| TInst ({ cl_path = ([], "String") }, []) ->
+							self#write ((self#use hxdynamicstr_type_path) ^ "::wrap(");
+							self#write_expr expr;
+							self#write ")"
+						| _ ->
+							self#write_expr expr
+					);
+					self#write (", '" ^ (field_name field) ^ "')")
+		(**
+			Write anonymous object declaration to output buffer
+		*)
+		method private write_expr_object_declaration fields =
+			match fields with
+				| [] ->  self#write ("new " ^ (self#use hxanon_type_path) ^ "()")
+				| _ ->
+					self#write ("new " ^ (self#use hxanon_type_path)  ^ "([\n");
+					self#indent_more;
+					let write_field (key, value) = self#write_array_item ~key:key value in
+					List.iter write_field fields;
+					self#indent_less;
+					self#write_indentation;
+					self#write "])"
+		(**
+			Writes specified type to output buffer depending on type of expression.
+		*)
+		method private write_type type_expr =
+			match type_expr.eexpr with
+				| TTypeExpr (TClassDecl tcls) ->
+					self#write (self#use_t (TInst (tcls, [])))
+				| _ ->
+					if is_string type_expr then
+						self#write_expr type_expr
+					else begin
+						self#write "(";
+						self#write_expr type_expr;
+						self#write "->phpClassName)";
+					end
+		(**
+			Write language specific expression declared in `php.PHP` extern
+		*)
+		method private write_expr_call_lang_extern expr args =
+			let name = match expr.eexpr with
+				| TField (_, FStatic (_, field)) -> field_name field
+				| _ -> fail self#pos __POS__
+			in
+			match name with
+				| "int" | "float"
+				| "string" | "bool"
+				| "object" | "array" -> self#write_expr_lang_cast name args
+				| "binop" -> self#write_expr_lang_binop args
+				| "instanceof" -> self#write_expr_lang_instanceof args
+				| "foreach" -> self#write_expr_lang_foreach args
+				| "construct" -> self#write_expr_lang_construct args
+				| "getField" -> self#write_expr_lang_get_field args
+				| "setField" -> self#write_expr_lang_set_field args
+				| "getStaticField" -> self#write_expr_lang_get_static_field args
+				| "setStaticField" -> self#write_expr_lang_set_static_field args
+				| "call" -> self#write_expr_lang_call args
+				| "staticCall" -> self#write_expr_lang_static_call args
+				| "arrayDecl" -> self#write_expr_lang_array_decl args
+				| "splat" -> self#write_expr_lang_splat args
+				| "suppress" -> self#write_expr_lang_suppress args
+				| "keepVar" -> ()
+				| _ -> fail self#pos __POS__
+		(**
+			Writes splat operator (for `php.Syntax.splat()`)
+		*)
+		method private write_expr_lang_splat args =
+			match args with
+				| [ args_expr ] ->
+					self#write "...";
+					self#write_expr args_expr
+				| _ -> fail self#pos __POS__
+		(**
+			Writes error suppression operator (for `php.Syntax.suppress()`)
+		*)
+		method private write_expr_lang_suppress args =
+			match args with
+				| [ args_expr ] ->
+					self#write "@";
+					self#write_expr args_expr
+				| _ -> fail self#pos __POS__
+		(**
+			Writes native array declaration (for `php.Syntax.arrayDecl()`)
+		*)
+		method private write_expr_lang_array_decl args =
+			self#write "[";
+			write_args buffer (fun e -> self#write_expr e) args;
+			self#write "]"
+		(**
+			Writes a call to instance method (for `php.Syntax.call()`)
+		*)
+		method private write_expr_lang_call args =
+			match args with
+				| obj_expr :: method_expr :: args ->
+					self#write_expr obj_expr;
+					self#write "->{";
+					self#write_expr method_expr;
+					self#write "}(";
+					write_args buffer (fun e -> self#write_expr e) args;
+					self#write ")"
+				| _ -> fail self#pos __POS__
+		(**
+			Writes a call to a static method (for `php.Syntax.staticCall()`)
+		*)
+		method private write_expr_lang_static_call args =
+			match args with
+				| type_expr :: method_expr :: args ->
+					self#write_type type_expr;
+					self#write "::{";
+					self#write_expr method_expr;
+					self#write "}(";
+					write_args buffer (fun e -> self#write_expr e) args;
+					self#write ")"
+				| _ -> fail self#pos __POS__
+		(**
+			Writes field access for reading (for `php.Syntax.getField()`)
+		*)
+		method private write_expr_lang_get_field args =
+			match args with
+				| obj_expr :: field_expr :: [] ->
+					self#write_expr obj_expr;
+					self#write "->{";
+					self#write_expr field_expr;
+					self#write "}"
+				| _ -> fail self#pos __POS__
+		(**
+			Writes field access for writing (for `php.Syntax.setField()`)
+		*)
+		method private write_expr_lang_set_field args =
+			match args with
+				| obj_expr :: field_expr :: value_expr :: [] ->
+					self#write_expr obj_expr;
+					self#write "->{";
+					self#write_expr field_expr;
+					self#write "}";
+					self#write " = ";
+					self#write_expr value_expr
+				| _ -> fail self#pos __POS__
+		(**
+			Writes static field access for reading (for `php.Syntax.getStaticField()`)
+		*)
+		method private write_expr_lang_get_static_field args =
+			match args with
+				| type_expr :: field_expr :: [] ->
+					self#write_type type_expr;
+					self#write "::${";
+					self#write_expr field_expr;
+					self#write "}"
+				| _ -> fail self#pos __POS__
+		(**
+			Writes static field access for writing (for `php.Syntax.setField()`)
+		*)
+		method private write_expr_lang_set_static_field args =
+			match args with
+				| type_expr :: field_expr :: value_expr :: [] ->
+					self#write_expr type_expr;
+					self#write "::${";
+					self#write_expr field_expr;
+					self#write "}";
+					self#write " = ";
+					self#write_expr value_expr
+				| _ -> fail self#pos __POS__
+		(**
+			Writes `new` expression with class name taken local variable (for `php.Syntax.construct()`)
+		*)
+		method private write_expr_lang_construct args =
+			let (class_expr, args) = match args with
+				| class_expr :: args -> (class_expr, args)
+				| _ -> fail self#pos __POS__
+			in
+			self#write "new ";
+			self#write_expr class_expr;
+			self#write "(";
+			write_args buffer (fun e -> self#write_expr e) args;
+			self#write ")"
+		(**
+			Writes native php type conversion to output buffer (e.g. `php.Syntax.int()`)
+		*)
+		method private write_expr_lang_cast type_name args =
+			match args with
+				| expr :: [] ->
+					let add_parentheses = match self#parent_expr with Some e -> is_access e | None -> false
+					and expr = match expr.eexpr with
+						| TLocal e -> expr
+						| _ -> parenthesis expr
+					in
+					if add_parentheses then self#write "(";
+					self#write ("(" ^ type_name ^")");
+					self#write_expr expr;
+					if add_parentheses then self#write ")"
+				| _ -> fail self#pos __POS__
+		(**
+			Generates binary operation to output buffer (for `php.Syntax.binop()`)
+		*)
+		method private write_expr_lang_binop args =
+			match args with
+				| val_expr1 :: operator_expr :: val_expr2 :: [] ->
+					let operator = match operator_expr.eexpr with
+						| TConst (TString operator) -> operator
+						| _ -> error_and_exit self#pos "Second argument for php.Syntax.binop() must be a constant string"
+					in
+					self#write "(";
+					self#write_expr val_expr1;
+					self#write (" " ^ operator ^ " ");
+					self#write_expr val_expr2;
+					self#write ")"
+				| _ -> fail self#pos __POS__
+		(**
+			Writes `instanceof` expression to output buffer (for `php.Syntax.instanceof()`)
+		*)
+		method private write_expr_lang_instanceof args =
+			match args with
+				| val_expr :: type_expr :: [] ->
+					self#write_expr val_expr;
+					self#write " instanceof ";
+					(match type_expr.eexpr with
+						| TTypeExpr (TClassDecl tcls) ->
+							self#write (self#use_t (TInst (tcls, [])))
+						| _ ->
+							self#write_expr type_expr;
+							if not (is_string type_expr) then self#write "->phpClassName"
+					)
+				| _ -> fail self#pos __POS__
+		(**
+			Writes `foreach` expression to output buffer (for `php.Syntax.foreach()`)
+		*)
+		method private write_expr_lang_foreach args =
+			match args with
+				| collection_expr :: { eexpr = TFunction fn } :: [] ->
+					let (key_name, value_name) = match fn.tf_args with
+						| ({ v_name = key_name }, _) :: ({ v_name = value_name }, _) :: [] -> (key_name, value_name)
+						| _ -> fail self#pos __POS__
+					and add_parentheses =
+						match collection_expr.eexpr with
+							| TLocal _ -> false
+							| _ -> true
+					in
+					self#write "foreach (";
+					if add_parentheses then self#write "(";
+					self#write_expr collection_expr;
+					if add_parentheses then self#write ")";
+					self#write (" as $" ^ key_name ^ " => $" ^ value_name ^ ") ");
+					self#write_as_block fn.tf_expr
+				| _ ->
+					error_and_exit self#pos "PHP.foreach() only accepts anonymous function declaration for second argument."
+		(**
+			Writes TCall to output buffer
+		*)
+		method private write_expr_call target_expr args =
+			let target_expr = reveal_expr target_expr in
+			(match target_expr.eexpr with
+				| TConst TSuper -> 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 ")";
+		(**
+			Writes a name of a function or a constant from global php namespace
+		*)
+		method private write_expr_php_global target_expr =
+			match target_expr.eexpr with
+				| TField (_, FStatic (_, field)) -> self#write (field_name field)
+				| _ -> fail self#pos __POS__
+		(**
+			Writes access to PHP class constant
+		*)
+		method private write_expr_php_class_const target_expr =
+			match target_expr.eexpr with
+				| TField (_, FStatic (ecls, field)) ->
+					self#write ((self#use_t (TInst (ecls, []))) ^ "::" ^ (field_name field))
+				| _ -> fail self#pos __POS__
+		(**
+			Writes TNew to output buffer
+		*)
+		method private write_expr_new inst_class args =
+			let needs_php_prefix = not inst_class.cl_extern in
+			self#write ("new " ^ (self#use ~prefix:needs_php_prefix inst_class.cl_path) ^ "(");
+			write_args buffer self#write_expr args;
+			self#write ")"
+		(**
+			Writes ternary operator expressions to output buffer
+		*)
+		method private write_expr_ternary condition if_expr (else_expr:texpr) pos =
+			let parent_is_if = match self#parent_expr with Some { eexpr = TIf _ } -> true | _ -> false in
+			if parent_is_if then self#write "(";
+			(match condition.eexpr with
+				| TParenthesis expr -> self#write_expr expr;
+				| _ -> self#write_expr else_expr
+			);
+			self#write " ? ";
+			self#write_expr if_expr;
+			self#write " : ";
+			self#write_expr else_expr;
+			if parent_is_if then self#write ")"
+		(**
+			Writes "if...else..." expression to output buffer
+		*)
+		method private write_expr_if condition if_expr (else_expr:texpr option) =
+			let is_ternary =
+				if self#parent_expr_is_block then
+					false
+				else
+					match (if_expr.eexpr, else_expr) with
+						| (TBlock _, _) | (_, Some { eexpr=TBlock _ }) -> false
+						| _ -> true
+			in
+			if is_ternary then
+				match else_expr with
+					| None -> fail self#pos __POS__
+					| Some expr ->
+						self#write_expr_ternary condition if_expr expr self#pos
+			else begin
+				self#write "if ";
+				self#write_expr condition;
+				self#write " ";
+				self#write_as_block if_expr;
+				(match else_expr with
+					| None -> ()
+					| Some expr ->
+						self#write " else ";
+						match expr.eexpr with
+							| TIf _ -> self#write_expr expr
+							| _ -> self#write_as_block expr
+				)
+			end
+		(**
+			Writes TWhile ("while..." or "do...while") to output buffer
+		*)
+		method private write_expr_while condition expr do_while =
+			match do_while with
+				| NormalWhile ->
+					self#write "while ";
+					self#write_expr condition;
+					self#write " ";
+					self#write_as_block ~unset_locals:true expr
+				| DoWhile ->
+					self#write "do ";
+					self#write_as_block ~unset_locals:true expr;
+					self#write " while ";
+					self#write_expr condition
+		(**
+			Writes TSwitch to output buffer
+		*)
+		method private write_expr_switch switch cases default =
+			let write_case (conditions, expr) =
+				List.iter
+					(fun condition ->
+						self#write_indentation;
+						self#write "case ";
+						self#write_expr condition;
+						self#write ":\n";
+					)
+					conditions;
+				self#indent_more;
+				self#write_indentation;
+				self#write_as_block ~inline:true expr;
+				self#write_statement "break";
+				self#indent_less
+			in
+			self#write "switch ";
+			self#write_expr switch;
+			self#write " {\n";
+			self#indent_more;
+			List.iter write_case cases;
+			(match default with
+				| None -> ()
+				| Some expr ->
+					self#write_line "default:";
+					self#indent_more;
+					self#write_indentation;
+					self#write_as_block ~inline:true expr;
+					self#write_statement "break";
+					self#indent_less
+			);
+			self#indent_less;
+			self#write_indentation;
+			self#write "}"
+		(**
+			Write TEnumParameter expression to output buffer
+		*)
+		method private write_expr_enum_parameter expr constructor index =
+			(match expr.eexpr with
+				| TConst TNull -> self#write "(null)"
+				| _ -> self#write_expr expr
+			);
+			self#write ("->params[" ^ (string_of_int index) ^ "]")
+		(**
+			Writes argument for function declarations or calls
+		*)
+		method write_arg with_optionals (arg_name, optional, (arg_type:Type.t)) =
+			self#write ("$" ^ arg_name ^ (if with_optionals && optional then " = null" else ""))
+		(**
+			Writes argument with optional value for function declarations
+		*)
+		method write_function_arg arg =
+			match arg with
+				| ({ v_name = arg_name; v_type = arg_type }, default_value) ->
+					vars#declared arg_name;
+					if is_ref arg_type then self#write "&";
+					self#write ("$" ^ arg_name);
+					match default_value with
+						| None -> ()
+						| Some const ->
+							self#write " = ";
+							self#write_expr_const const
+	end
+
+(**
+	Builds enum contents
+*)
+class enum_builder ctx (enm:tenum) =
+	object (self)
+		inherit type_builder ctx (get_wrapper (TEnumDecl enm))
+		(**
+			Writes type declaration line to output buffer.
+			E.g. "class SomeClass extends Another implements IFace"
+		*)
+		method private write_declaration =
+			self#write_doc (DocClass enm.e_doc);
+			self#write_line ("class " ^ self#get_name ^ " extends " ^ (self#use hxenum_type_path))
+		(**
+			Writes type body to output buffer.
+			E.g. for "class SomeClass { <BODY> }" writes <BODY> part.
+		*)
+		method private write_body =
+			let write_empty_lines = ref false in
+			PMap.iter
+				(fun name field ->
+					if !write_empty_lines then
+						self#write_empty_lines
+					else
+						write_empty_lines := true;
+					self#write_constructor name field
+				)
+				enm.e_constrs;
+			self#write_reflection
+		(**
+			Writes constructor declaration to output buffer
+		*)
+		method private write_constructor name (field:tenum_field) =
+			let args =
+				match follow field.ef_type with
+					| TFun (args, _) -> args
+					| TEnum _ -> []
+					| _ -> fail field.ef_pos __POS__
+			in
+			self#indent 1;
+			self#write_doc (DocMethod (args, TEnum (enm, []), field.ef_doc));
+			self#write_indentation;
+			self#write ("static public function " ^ name ^ " (");
+			write_args buffer (self#write_arg true) args;
+			self#write ")\n";
+			self#write_line "{";
+			self#indent_more;
+			self#write_indentation;
+			self#write "return ";
+			let index_str = string_of_int field.ef_index in
+			(match args with
+				| [] -> self#write ((self#use hxenum_type_path) ^ "::singleton(static::class, '" ^ name ^ "', " ^ index_str ^")")
+				| args ->
+					self#write ("new " ^ self#get_name ^ "('" ^ name ^ "', " ^ index_str ^", [");
+					write_args buffer (fun (name, _, _) -> self#write ("$" ^ name)) args;
+					self#write "])"
+			);
+			self#write ";\n";
+			self#indent_less;
+			self#write_line "}"
+		(**
+			Writes special methods for reflection
+		*)
+		method private write_reflection =
+			(* __hx__list *)
+			self#write_empty_lines;
+			self#indent 1;
+			self#write_line "/**";
+			self#write_line " * Returns array of (constructorIndex => constructorName)";
+			self#write_line " *";
+			self#write_line " * @return string[]";
+			self#write_line " */";
+			self#write_line "static public function __hx__list ()";
+			self#write_line "{";
+			self#indent_more;
+			self#write_line "return [";
+			self#indent_more;
+			PMap.iter
+				(fun name field ->
+					self#write_line ((string_of_int field.ef_index) ^ " => '" ^ name ^ "',")
+				)
+				enm.e_constrs;
+			self#indent_less;
+			self#write_statement "]";
+			self#indent_less;
+			self#write_line "}";
+			(* __hx__paramsCount *)
+			self#write_empty_lines;
+			self#indent 1;
+			self#write_line "/**";
+			self#write_line " * Returns array of (constructorName => parametersCount)";
+			self#write_line " *";
+			self#write_line " * @return int[]";
+			self#write_line " */";
+			self#write_line "static public function __hx__paramsCount ()";
+			self#write_line "{";
+			self#indent_more;
+			self#write_line "return [";
+			self#indent_more;
+			PMap.iter
+				(fun name field ->
+					let count = match follow field.ef_type with
+						| TFun (params, _) -> List.length params
+						| TEnum _ -> 0
+						| _ -> fail field.ef_pos __POS__
+					in
+					self#write_line ("'" ^ name ^ "' => " ^ (string_of_int count) ^ ",")
+				)
+				enm.e_constrs;
+			self#indent_less;
+			self#write_statement "]";
+			self#indent_less;
+			self#write_line "}";
+		(**
+			Method `__hx__init` is not needed for enums
+		**)
+		method private write_hx_init_body = ()
+		(**
+			No need for additional initialization of enum instances
+		*)
+		method private write_instance_initialization = ()
+		(**
+			No need for additional type initialization for enums
+		*)
+		method private write_pre_hx_init = ()
+	end
+
+(**
+	Builds class contents
+*)
+class class_builder ctx (cls:tclass) =
+	object (self)
+		inherit type_builder ctx (get_wrapper (TClassDecl cls)) as super
+		(**
+			Indicates if type should be declared as `final`
+		*)
+		method is_final =
+			if not (Meta.has Meta.Final cls.cl_meta) then
+				false
+			else begin
+				let hacked = ref false in
+				List.iter
+					(fun com_type ->
+						if not !hacked then
+							match com_type with
+								| TClassDecl tcls ->
+									if self#extended_by tcls then hacked := Meta.has Meta.Hack tcls.cl_meta
+								| _ -> ()
+					)
+					ctx.types;
+				not !hacked
+			end
+		(**
+			Indicates if `field` should be declared as `final`
+		*)
+		method is_final_field (field:tclass_field) : bool =
+			Meta.has Meta.Final field.cf_meta
+		(**
+			Recursively check if current class is a parent class for a `child`
+		*)
+		method private extended_by child =
+			let result =
+				if child == cls then
+					false
+				else
+					let rec check current =
+						match current.cl_super with
+							| None -> false
+							| Some (scls, _) ->
+								if scls == cls then true else check scls
+					in
+					check child
+			in
+			result
+		(**
+			Writes type declaration line to output buffer.
+			E.g. "class SomeClass extends Another implements IFace"
+		*)
+		method private write_declaration =
+			if self#is_final then self#write "final ";
+			self#write_doc (DocClass cls.cl_doc);
+			self#write (if cls.cl_interface then "interface " else "class ");
+			self#write self#get_name;
+			(
+				match cls.cl_super with
+					| None -> ();
+					| Some (super_class, params) ->
+						let super_name = self#use_t (TInst (super_class, params)) in
+						self#write (" extends " ^ super_name)
+			);
+			if List.length cls.cl_implements > 0 then begin
+				self#write (if cls.cl_interface then " extends " else " implements ");
+				let use_interface iface =
+					match iface with
+						| (i, params) -> self#use_t (TInst (i, params))
+				in
+				let interfaces = List.map use_interface cls.cl_implements in
+				self#write (String.concat ", " interfaces);
+			end;
+			self#write "\n"
+		(**
+			Returns either user-defined constructor or creates empty constructor if instance initialization is required.
+		*)
+		method private get_constructor : tclass_field option =
+			match cls.cl_constructor with
+				| Some field -> Some field
+				| None ->
+					if not self#constructor_is_required then
+						None
+					else
+						Some {
+							cf_name = "new";
+							cf_type = TFun ([], get_void ctx);
+							cf_public = true;
+							cf_pos = cls.cl_pos;
+							cf_name_pos = cls.cl_pos;
+							cf_doc = None;
+							cf_meta = [];
+							cf_kind = Method MethNormal;
+							cf_params = [];
+							cf_expr = Some {
+								eexpr = TFunction {
+									tf_args = [];
+									tf_type = get_void ctx;
+									tf_expr = { eexpr = TBlock []; epos = cls.cl_pos; etype = get_void ctx; };
+								};
+								epos = cls.cl_pos;
+								etype = get_void ctx;
+							};
+							cf_expr_unoptimized = None;
+							cf_overloads = [];
+						}
+		(**
+			Writes type body to output buffer.
+			E.g. for "class SomeClass { <BODY> }" writes <BODY> part.
+		*)
+		method private write_body =
+			let at_least_one_field_written = ref false in
+			let write_if_constant _ field =
+				match field.cf_kind with
+					| Var { v_read = AccInline; v_write = AccNever } ->
+						at_least_one_field_written := true;
+						self#write_field true field
+					| _ -> ()
+			and write_if_method is_static _ field =
+				match field.cf_kind with
+					| Var _ -> ()
+					| Method MethDynamic when is_static -> ()
+					| Method _ ->
+						if !at_least_one_field_written then self#write_empty_lines;
+						at_least_one_field_written := true;
+						self#write_field is_static field
+			and write_if_var is_static _ field =
+				match field.cf_kind with
+					| Var { v_read = AccInline; v_write = AccNever } -> ()
+					| Method MethDynamic ->
+						at_least_one_field_written := true;
+						let kind = Var { v_read = AccNormal; v_write = AccNormal; } in
+						self#write_field is_static { field with cf_kind = kind }
+					| Var _ ->
+						at_least_one_field_written := true;
+						self#write_field is_static field
+					| Method _ -> ()
+			in
+			if boot_type_path = self#get_type_path then begin
+				self#write_php_prefix ();
+				at_least_one_field_written := true
+			end;
+		 	if not cls.cl_interface then begin
+		 		(* Inlined statc vars (constants) *)
+				PMap.iter (write_if_constant) cls.cl_statics;
+				if !at_least_one_field_written then self#write_empty_lines;
+				at_least_one_field_written := false;
+		 		(* Statc vars *)
+				PMap.iter (write_if_var true) cls.cl_statics;
+				if !at_least_one_field_written then self#write_empty_lines;
+				at_least_one_field_written := false;
+				(* instance vars *)
+				PMap.iter (write_if_var false) cls.cl_fields
+			end;
+			(* Statc methods *)
+			PMap.iter (write_if_method true) cls.cl_statics;
+			(* Constructor *)
+			(match self#get_constructor with
+				| Some field -> write_if_method false "new" field
+				| None -> ()
+			);
+			(* Instance methods *)
+			PMap.iter (write_if_method false) cls.cl_fields;
+			(* Generate `__toString()` if not defined by user, but has `toString()` *)
+			self#write_toString_if_required
+		method private write_toString_if_required =
+			if PMap.exists "toString" cls.cl_fields then
+				if (not cls.cl_interface) && (not (PMap.exists "__toString" cls.cl_statics)) && (not (PMap.exists "__toString" cls.cl_fields)) then
+					begin
+						self#write_empty_lines;
+						self#indent 1;
+						self#write_line "public function __toString() {";
+						self#indent_more;
+						self#write_line "return $this->toString();";
+						self#indent_less;
+						self#write_line "}"
+					end
+		(**
+			Check if this class requires constructor to be generated even if there is no user-defined one
+		*)
+		method private constructor_is_required =
+			if List.length self#get_namespace > 0 then
+				false
+			else begin
+				let required = ref false in
+				List.iter
+					(fun field ->
+						if not !required then
+							required := (String.lowercase field.cf_name = String.lowercase self#get_name)
+					)
+					(cls.cl_ordered_statics @ cls.cl_ordered_fields);
+				!required
+			end
+		(**
+			Writes `--php-prefix` value as class constant PHP_PREFIX
+		*)
+		method private write_php_prefix () =
+			let prefix = String.concat "\\" (get_php_prefix ctx) in
+			let indentation = String.length indentation in
+			self#indent 1;
+			self#write_statement ("const PHP_PREFIX = \"" ^ (String.escaped prefix) ^ "\"");
+			self#indent indentation
+		(**
+			Writes expressions for `__hx__init` method
+		*)
+		method private write_hx_init_body =
+			(* `static dynamic function` initialization *)
+			let write_dynamic_method_initialization field =
+				let field_access = "self::$" ^ (field_name field) in
+				self#write_indentation;
+				self#write (field_access ^ " = ");
+				(match field.cf_expr with
+					| Some expr -> self#write_expr expr
+					| None -> fail field.cf_pos __POS__
+				);
+				self#write ";\n"
+			in
+			PMap.iter
+				(fun _ field ->
+					match field.cf_kind with
+						| Method MethDynamic -> write_dynamic_method_initialization field
+						| _ -> ()
+				)
+				cls.cl_statics;
+			(* `static var` initialization *)
+			let write_var_initialization _ field =
+				let write_assign expr =
+					self#write_indentation;
+					self#write ("self::$" ^ (field_name field) ^ " = ");
+					self#write_expr expr
+				in
+				(* Do not generate fields for RTTI meta, because this generator uses another way to store it *)
+				let is_auto_meta_var = field.cf_name = "__meta__" && (has_rtti_meta ctx wrapper#get_module_type) in
+				if (is_var_with_nonconstant_expr field) && (not is_auto_meta_var) then begin
+					(match field.cf_expr with
+						| None -> ()
+						(* There can be not-inlined blocks when compiling with `-debug` *)
+						| Some { eexpr = TBlock exprs } ->
+							let rec write_per_line exprs =
+								match exprs with
+									| [] -> ()
+									| [expr] -> write_assign expr
+									| expr :: rest ->
+										self#write_indentation;
+										self#write_expr expr;
+										self#write ";\n";
+										write_per_line rest
+							in
+							write_per_line exprs
+						| Some expr -> write_assign expr
+					);
+					self#write ";\n"
+				end
+			in
+			PMap.iter write_var_initialization cls.cl_statics
+		(**
+			Writes single field to output buffer.
+		*)
+		method private write_field is_static field =
+			match field.cf_kind with
+				| Var { v_read = AccInline; v_write = AccNever } -> self#write_const field
+				| Var _ when is_real_var field ->
+					(* Do not generate fields for RTTI meta, because this generator uses another way to store it *)
+					let is_auto_meta_var = is_static && field.cf_name = "__meta__" && (has_rtti_meta ctx wrapper#get_module_type) in
+					if not is_auto_meta_var then self#write_var field is_static;
+				| Var _ -> ()
+				| Method MethMacro -> ()
+				| Method MethDynamic when is_static -> ()
+				| Method MethDynamic -> self#write_dynamic_method field
+				| Method _ -> self#write_method field is_static
+		(**
+			Writes var-field to output buffer
+		*)
+		method private write_var field is_static =
+			self#indent 1;
+			self#write_doc (DocVar (self#use_t field.cf_type, field.cf_doc));
+			self#write_indentation;
+			if is_static then self#write "static ";
+			let visibility = get_visibility field.cf_meta in
+			self#write (visibility ^ " $" ^ (field_name field));
+			match field.cf_expr with
+				| None -> self#write ";\n"
+				| Some expr ->
+					match expr.eexpr with
+						| TConst _ ->
+							self#write " = ";
+							self#write_expr expr;
+							self#write ";\n"
+						| _ -> self#write ";\n"
+		(**
+			Writes "inline var" to output buffer as constant
+		*)
+		method private write_const field =
+			self#indent 1;
+			self#write_doc (DocVar (self#use_t field.cf_type, field.cf_doc));
+			self#write_indentation;
+			self#write ("const " ^ (field_name field) ^ " = ");
+			match field.cf_expr with
+				| None -> fail self#pos __POS__
+				| Some expr ->
+					self#write_expr expr;
+					self#write ";\n"
+		(**
+			Writes method to output buffer
+		*)
+		method private write_method field is_static =
+			vars#clear;
+			self#indent 1;
+			let (args, return_type) = get_function_signature field in
+			List.iter (fun (arg_name, _, _) -> vars#declared arg_name) args;
+			self#write_doc (DocMethod (args, return_type, field.cf_doc));
+			self#write_indentation;
+			if self#is_final_field field then self#write "final ";
+			if is_static then self#write "static ";
+			self#write ((get_visibility field.cf_meta) ^ " ");
+			match field.cf_expr with
+				| None ->
+					self#write ("function " ^ (field_name field) ^ " (");
+					write_args buffer (self#write_arg true) args;
+					self#write ")";
+					self#write " ;\n"
+				| Some { eexpr = TFunction fn } ->
+					let name = if field.cf_name = "new" then "__construct" else (field_name field) in
+					self#write_expr_function ~name:name fn;
+					self#write "\n"
+				| _ -> fail field.cf_pos __POS__
+		(**
+			Writes dynamic method to output buffer.
+			Only for non-static methods. Static methods are created as static vars in `__hx__init`.
+		*)
+		method private write_dynamic_method field =
+			vars#clear;
+			self#indent 1;
+			let (args, return_type) = get_function_signature field in
+			List.iter (fun (arg_name, _, _) -> vars#declared arg_name) args;
+			self#write_doc (DocMethod (args, return_type, field.cf_doc));
+			self#write_indentation;
+			self#write ((get_visibility field.cf_meta) ^ " function " ^ (field_name field));
+			(match field.cf_expr with
+				| None -> (* interface *)
+					self#write " (";
+					write_args buffer (self#write_arg true) args;
+					self#write ");\n";
+				| Some { eexpr = TFunction fn } -> (* normal class *)
+					self#write " (";
+					write_args buffer self#write_function_arg fn.tf_args;
+					self#write ")\n";
+					self#write_line "{";
+					self#indent_more;
+					self#write_indentation;
+					let field_access = "$this->" ^ (field_name field)
+					and default_value = "$this->__hx__default__" ^ (field_name field) in
+					self#write ("if (" ^ field_access ^ " !== " ^ default_value ^ ") return call_user_func_array(" ^ field_access ^ ", func_get_args());\n");
+					self#write_fake_block fn.tf_expr;
+					self#indent_less;
+					self#write_line "}";
+					(* Don't forget to create a field for default value *)
+					self#write_statement ("protected $__hx__default__" ^ (field_name field))
+				| _ -> fail field.cf_pos __POS__
+			);
+		(**
+			Writes initialization code for instances of this class
+		*)
+		method private write_instance_initialization =
+			let init_dynamic_method field =
+				let field_name = field_name field in
+				let default_field = "$this->__hx__default__" ^ field_name in
+				self#write_line ("if (!" ^ default_field ^ ") {");
+				self#indent_more;
+				self#write_statement (default_field ^ " = new " ^ (self#use hxclosure_type_path) ^ "($this, '" ^ field_name ^ "')");
+				self#write_statement ("if ($this->" ^ field_name ^ " === null) $this->" ^ field_name ^ " = " ^ default_field);
+				self#indent_less;
+				self#write_line "}"
+			in
+			PMap.iter
+				(fun _ field ->
+					match field.cf_kind with
+						| Method MethDynamic -> init_dynamic_method field
+						| _ -> ()
+				)
+				cls.cl_fields
+		(**
+			Writes additional initialization code, which should be called before `__hx__init()`
+		*)
+		method private write_pre_hx_init =
+			let getters = ref []
+			and setters = ref [] in
+			let collect field =
+				match field.cf_kind with
+					| Var { v_read = read; v_write = write } ->
+						if read = AccCall then getters := field.cf_name :: !getters;
+						if write = AccCall then setters := field.cf_name :: !setters;
+					| _ -> ()
+			in
+			List.iter collect cls.cl_ordered_fields;
+			List.iter collect cls.cl_ordered_statics;
+			let rec write lst =
+				match lst with
+					| [] -> ()
+					| [item] -> self#write_line ("'" ^ item ^ "' => true");
+					| item :: rest ->
+						self#write_line ("'" ^ item ^ "' => true,");
+						write rest
+			and type_name = get_full_type_name ~escape:true ~omit_first_slash:true (add_php_prefix ctx wrapper#get_type_path) in
+			let write_register register_method lst =
+				self#write_line ((self#use boot_type_path) ^ "::" ^ register_method ^ "('" ^ type_name ^ "', [");
+				self#indent_more;
+				write lst;
+				self#indent_less;
+				self#write_statement "])"
+			in
+			if List.length !getters > 0 then write_register "registerGetters" !getters;
+			if List.length !setters > 0 then write_register "registerSetters" !setters;
+	end
+
+(**
+	Handles generation process
+*)
+class generator (com:context) =
+	object (self)
+		val mutable build_dir = ""
+		val root_dir = com.file
+		val mutable init_types = []
+		val mutable boot : (type_builder * string) option  = None
+		(**
+			Perform required actions before actual php files generation
+		*)
+		method initialize =
+			self#create_output_dirs;
+		(**
+			Generates php file for specified type
+		*)
+		method generate (builder:type_builder) =
+			let contents = builder#get_contents
+			and namespace = builder#get_namespace
+			and name = builder#get_name in
+			let filename = (create_dir_recursive (build_dir :: namespace)) ^ "/" ^ name ^ ".php" in
+			let channel = open_out filename in
+			output_string channel contents;
+			output_string channel ("\n//Haxe source file: " ^ builder#get_source_file ^ "\n");
+			close_out channel;
+			if builder#get_type_path = boot_type_path then
+				boot <- Some (builder, filename)
+			else if builder#has_magic_init then
+				init_types <- (get_full_type_name (namespace, name)) :: init_types
+		(**
+			Perform actions which should be executed after all classes were processed
+		*)
+		method finalize : unit =
+			self#generate_magic_init;
+			self#generate_entry_point
+		(**
+			Generates calls to static __init__ methods in Boot.php
+		*)
+		method generate_magic_init : unit =
+			match init_types with
+				| [] -> ()
+				| _ ->
+					match boot with
+						| None -> fail dummy_pos __POS__
+						| Some (_, filename) ->
+							let channel = open_out_gen [Open_creat; Open_text; Open_append] 0o644 filename in
+							List.iter
+								(fun class_name -> output_string channel (class_name ^ "::__hx__init();\n"))
+								init_types;
+							close_out channel
+		(**
+			Creates `index.php` which can be used as entry-point for standalone Haxe->PHP app
+		*)
+		method generate_entry_point =
+			match self#get_main_class with
+				| None -> ()
+				| Some main_class ->
+					let channel = open_out (root_dir ^ "/index.php") in
+					output_string channel "<?php\n";
+					output_string channel ("set_include_path(__DIR__.'/" ^ (String.concat "/" self#get_lib_path) ^ "');\n");
+					output_string channel "spl_autoload_register(\n";
+					output_string channel "	function($class){\n";
+					output_string channel "		$file = stream_resolve_include_path(str_replace('\\\\', '/', $class) .'.php');\n";
+					output_string channel "		if ($file) {\n";
+					output_string channel "			include_once $file;\n";
+					output_string channel "		}\n";
+					output_string channel "	}\n";
+					output_string channel ");\n";
+					(match boot with
+						| None -> fail dummy_pos __POS__
+						| Some (builder, filename) ->
+							let boot_class = get_full_type_name (add_php_prefix com builder#get_type_path) in
+							output_string channel (boot_class ^ "::__hx__init();\n")
+					);
+					output_string channel (main_class ^ "::main();\n");
+					close_out channel
+		(**
+			Create necessary directories  before processing types
+		*)
+		method private create_output_dirs =
+			let build_path = (root_dir :: self#get_lib_path) in
+			build_dir <- create_dir_recursive build_path
+		(**
+			Returns path from `index.php` to directory which will contain all generated classes
+		*)
+		method private get_lib_path : string list =
+			match com.php_lib with
+				| None -> ["lib"];
+				| Some path -> (Str.split (Str.regexp "/")  path)
+		(**
+			Returns FQN for main class if defined
+		*)
+		method private get_main_class : string option =
+			match com.main_class with
+				| None -> None
+				| Some type_path -> Some (get_full_type_name (add_php_prefix com type_path))
+	end
+
+(**
+	Entry point to Genphp7
+*)
+let generate (com:context) =
+	let gen = new generator com in
+	gen#initialize;
+	let generate com_type =
+		let wrapper = get_wrapper com_type in
+		if wrapper#needs_generation then
+			match com_type with
+				| TClassDecl cls -> gen#generate (new class_builder com cls);
+				| TEnumDecl enm -> gen#generate (new enum_builder com enm);
+				| TTypeDecl typedef -> ();
+				| TAbstractDecl abstr -> ()
+	in
+	List.iter generate com.types;
+	gen#finalize;
+	Hashtbl.iter
+		(fun name data ->
+			write_resource com.file name data
+		)
+		com.resources;
+	clear_wrappers ();

+ 12 - 2
src/main.ml

@@ -277,7 +277,14 @@ module Initialize = struct
 				add_std "lua";
 				"lua"
 			| Php ->
-				add_std "php";
+				if Common.php7 com then
+					begin
+						com.package_rules <- PMap.add "php" (Directory "php7") com.package_rules;
+						com.package_rules <- PMap.add "php7" Forbidden com.package_rules;
+						add_std "php7"
+					end
+				else
+					add_std "php";
 				"php"
 			| Cpp ->
 				Common.define_value com Define.HxcppApiLevel "331";
@@ -346,7 +353,10 @@ let generate tctx ext xml_out interp swf_header =
 		| Lua ->
 			Genlua.generate,"lua"
 		| Php ->
-			Genphp.generate,"php"
+			if Common.php7 com then
+				Genphp7.generate,"php"
+			else
+				Genphp.generate,"php"
 		| Cpp ->
 			Gencpp.generate,"cpp"
 		| Cs ->

+ 3 - 3
src/optimization/analyzerTexpr.ml

@@ -123,7 +123,7 @@ let rec can_be_used_as_value com e =
 		(* | TCall _ | TNew _ when (match com.platform with Cpp | Php -> true | _ -> false) -> raise Exit *)
 		| TReturn _ | TThrow _ | TBreak | TContinue -> raise Exit
 		| TUnop((Increment | Decrement),_,_) when not (target_handles_unops com) -> raise Exit
-		| TNew _ when com.platform = Php -> raise Exit
+		| TNew _ when com.platform = Php && not (Common.php7 com) -> raise Exit
 		| TFunction _ -> ()
 		| _ -> Type.iter loop e
 	in
@@ -682,7 +682,7 @@ module Fusion = struct
 							let el = List.map replace el in
 							let e2 = replace e2 in
 							e2,el
-						| Php | Cpp  when not (Common.defined com Define.Cppia) ->
+						| Php | Cpp  when not (Common.defined com Define.Cppia) && not (Common.php7 com) ->
 							let is_php_safe e1 =
 								let rec loop e = match e.eexpr with
 									| TCall _ -> raise Exit
@@ -794,7 +794,7 @@ module Fusion = struct
 							let e3 = replace e3 in
 							if not !found && has_state_read ir then raise Exit;
 							{e with eexpr = TBinop(OpAssign,{ea with eexpr = TArray(e1,e2)},e3)}
-						| TBinop(op,e1,e2) when (match com.platform with Cpp | Php -> true | _ -> false) ->
+						| TBinop(op,e1,e2) when (match com.platform with Cpp | Php when not (Common.php7 com) -> true | _ -> false) ->
 							let e1 = replace e1 in
 							let temp_found = !found in
 							found := false;

+ 1 - 1
src/optimization/filters.ml

@@ -901,7 +901,7 @@ let add_meta_field ctx t = match t with
 			f.cf_expr <- Some e;
 			let can_deal_with_interface_metadata () = match ctx.com.platform with
 				| Flash when Common.defined ctx.com Define.As3 -> false
-				| Php -> false
+				| Php when not (Common.php7 ctx.com) -> false
 				| _ -> true
 			in
 			if c.cl_interface && not (can_deal_with_interface_metadata()) then begin

+ 1 - 1
src/typing/typer.ml

@@ -970,7 +970,7 @@ let error_require r p =
 		error "This field is not available with the current compilation flags" p
 	else
 	let r = if r = "sys" then
-		"a system platform (php,neko,cpp,etc.)"
+		"a system platform (php,php7,neko,cpp,etc.)"
 	else try
 		if String.sub r 0 5 <> "flash" then raise Exit;
 		let _, v = ExtString.String.replace (String.sub r 5 (String.length r - 5)) "_" "." in

+ 4 - 4
std/DateTools.hx

@@ -114,16 +114,16 @@ class DateTools {
 		supported.
 
 		```haxe
-		var t = DateTools.format(Date.now(), "%Y-%m-%d_%H:%M:%S"); 
+		var t = DateTools.format(Date.now(), "%Y-%m-%d_%H:%M:%S");
 		// 2016-07-08_14:44:05
 
-		var t = DateTools.format(Date.now(), "%r"); 
+		var t = DateTools.format(Date.now(), "%r");
 		// 02:44:05 PM
 
-		var t = DateTools.format(Date.now(), "%T"); 
+		var t = DateTools.format(Date.now(), "%T");
 		// 14:44:05
 
-		var t = DateTools.format(Date.now(), "%F"); 
+		var t = DateTools.format(Date.now(), "%F");
 		// 2016-07-08
 		```
 	**/

+ 1 - 1
std/haxe/CallStack.hx

@@ -175,7 +175,7 @@ class CallStack {
 			}
 			return a;
 		#elseif php
-			return makeStack("%e");
+			return makeStack("%e");		
 		#elseif cpp
 			var s:Array<String> = untyped __global__.__hxcpp_get_exception_stack();
 			return makeStack(s);

+ 1 - 1
std/haxe/Int64.hx

@@ -454,7 +454,7 @@ private typedef __Int64 = ___Int64;
 
 private class ___Int64 {
 	public var high : Int32;
-	public var low : Int32; 
+	public var low : Int32;
 
 	public inline function new( high, low ) {
 		this.high = high;

+ 4 - 2
std/haxe/Log.hx

@@ -35,8 +35,8 @@ class Log {
 
 		This method can be rebound to a custom function:
 			var oldTrace = haxe.Log.trace; // store old function
-			haxe.Log.trace = function(v, ?infos) { 
-			  // handle trace 
+			haxe.Log.trace = function(v, ?infos) {
+			  // handle trace
 			}
 			...
 			haxe.Log.trace = oldTrace;
@@ -62,6 +62,8 @@ class Log {
 			}
 		#elseif js
 			untyped js.Boot.__trace(v,infos);
+		#elseif (php && php7)
+			php.Boot.trace(v, infos);
 		#elseif php
 			if (infos!=null && infos.customParams!=null) {
 				var extra:String = "";

+ 7 - 2
std/haxe/Serializer.hx

@@ -377,7 +377,7 @@ class Serializer {
 				#end
 			default:
 				if( useCache ) cache.pop();
-				if( #if flash try v.hxSerialize != null catch( e : Dynamic ) false #elseif (cs || java || python) Reflect.hasField(v, "hxSerialize") #else v.hxSerialize != null #end  ) {
+				if( #if flash try v.hxSerialize != null catch( e : Dynamic ) false #elseif (cs || java || python) Reflect.hasField(v, "hxSerialize") #elseif (php && php7) php.Global.method_exists(v, 'hxSerialize') #else v.hxSerialize != null #end  ) {
 					buf.add("C");
 					serializeString(Type.getClassName(c));
 					if( useCache ) cache.push(v);
@@ -476,8 +476,13 @@ class Serializer {
 				buf.add(0);
 			else {
 				buf.add(l);
-				for( i in 0...l )
+				for( i in 0...l ) {
+					#if (php && php7)
+					serialize(v.params[i]);
+					#elseif php
 					serialize(untyped __field__(v, __php__("params"), i));
+					#end
+				}
 			}
 			#elseif (java || cs || python || hl)
 			if( useEnumIndex ) {

+ 1 - 1
std/haxe/Timer.hx

@@ -179,7 +179,7 @@ class Timer {
 			return Sys.cpuTime();
 		#elseif sys
 			return Sys.time();
-		
+
 		#else
 			return 0;
 		#end

+ 2 - 0
std/haxe/io/BytesData.hx

@@ -27,6 +27,8 @@ package haxe.io;
 	typedef BytesData =	flash.utils.ByteArray;
 #elseif php
 	typedef BytesData = php.BytesData;
+#elseif php
+	typedef BytesData = php.NativeString;
 #elseif cpp
 	typedef BytesData = Array< cpp.UInt8 >;
 #elseif java

+ 17 - 17
std/haxe/io/Input.hx

@@ -65,17 +65,17 @@ class Input {
 			throw Error.OutsideBounds;
 		try {
 			while( k > 0 ) {
-			    #if neko
-				    untyped __dollar__sset(b,pos,readByte());
-			    #elseif php
-				    b.set(pos, readByte());
-			    #elseif cpp
-				    b[pos] = untyped readByte();
-			    #else
-				    b[pos] = cast readByte();
-			    #end
-			    pos++;
-			    k--;
+				#if neko
+					untyped __dollar__sset(b,pos,readByte());
+				#elseif php
+					b.set(pos, readByte());
+				#elseif cpp
+					b[pos] = untyped readByte();
+				#else
+					b[pos] = cast readByte();
+				#end
+				pos++;
+				k--;
 			}
 		} catch (eof: haxe.io.Eof){}
 		return len-k;
@@ -284,7 +284,7 @@ class Input {
 		// php will overflow integers.  Convert them back to signed 32-bit ints.
 		var n = bigEndian ? ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24) : ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
 		if (n & 0x80000000 != 0)
-		    return ( n | 0x80000000);
+			return ( n | 0x80000000);
 		else return n;
 #elseif lua
 		var n = bigEndian ? ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24) : ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
@@ -317,11 +317,11 @@ class Input {
 
 #if (flash || js || python)
 	function getDoubleSig(bytes:Array<Int>)
-    {
-        return (((bytes[1]&0xF) << 16) | (bytes[2] << 8) | bytes[3] ) * 4294967296. +
-            (bytes[4] >> 7) * 2147483648 +
-            (((bytes[4]&0x7F) << 24) | (bytes[5] << 16) | (bytes[6] << 8) | bytes[7]);
-    }
+	{
+		return (((bytes[1]&0xF) << 16) | (bytes[2] << 8) | bytes[3] ) * 4294967296. +
+			(bytes[4] >> 7) * 2147483648 +
+			(((bytes[4]&0x7F) << 24) | (bytes[5] << 16) | (bytes[6] << 8) | bytes[7]);
+	}
 #end
 
 }

+ 5 - 3
std/haxe/rtti/Meta.hx

@@ -46,11 +46,11 @@ class Meta {
 	private static function isInterface(t:Dynamic):Bool {
 		#if java
 			return java.Lib.toNativeType(t).isInterface();
-		#elseif cs
+	#elseif cs
 			return cs.Lib.toNativeType(t).IsInterface;
 		#elseif (flash && as3)
 			return untyped flash.Lib.describeType(t).factory.extendsClass.length() == 0;
-		#elseif php
+		#elseif (php && !php7)
 			return untyped __php__("{0} instanceof _hx_interface", t);
 		#else
 			throw "Something went wrong";
@@ -59,7 +59,9 @@ class Meta {
 
 	private static function getMeta(t:Dynamic):MetaObject
 	{
-#if (java || cs || php || (flash && as3))
+#if (php && php7)
+		return php.Boot.getMeta(t.phpClassName);
+#elseif (java || cs || php || (flash && as3))
 		var ret = Reflect.field(t, "__meta__");
 		if (ret == null && Std.is(t,Class))
 		{

+ 8 - 8
std/haxe/xml/Parser.hx

@@ -52,27 +52,27 @@ class XmlParserException
 	 * the XML parsing error message
 	 */
 	public var message:String;
-	
+
 	/**
 	 * the line number at which the XML parsing error occured
 	 */
 	public var lineNumber:Int;
-	
+
 	/**
 	 * the character position in the reported line at which the parsing error occured
 	 */
 	public var positionAtLine:Int;
-	
+
 	/**
 	 * the character position in the XML string at which the parsing error occured
 	 */
 	public var position:Int;
-	
+
 	/**
 	 * the invalid XML string
 	 */
 	public var xml:String;
-	
+
 	public function new(message:String, xml:String, position:Int)
 	{
 		this.xml = xml;
@@ -80,7 +80,7 @@ class XmlParserException
 		this.position = position;
 		lineNumber = 1;
 		positionAtLine = 0;
-		
+
 		for( i in 0...position)
 		{
 			var c = xml.fastCodeAt(i);
@@ -92,7 +92,7 @@ class XmlParserException
 			}
 		}
 	}
-	
+
 	public function toString():String
 	{
 		return Type.getClassName(Type.getClass(this)) + ": " + message + " at line " + lineNumber + " char " + positionAtLine;
@@ -113,7 +113,7 @@ class Parser
 
 	/**
 	 * Parses the String into an XML Document. Set strict parsing to true in order to enable a strict check of XML attributes and entities.
-	 * 
+	 *
 	 * @throws haxe.xml.XmlParserException
 	 */
 	static public function parse(str:String, strict = false)

+ 13 - 0
std/php7/ArrayAccess.hx

@@ -0,0 +1,13 @@
+package php;
+
+/**
+	Native PHP interface.
+	@see http://php.net/manual/en/class.arrayaccess.php
+**/
+@:native('ArrayAccess')
+extern interface ArrayAccess<K,V> {
+	function offsetExists( offset:K ) : Bool;
+	function offsetGet( offset:K ) : V;
+	function offsetSet( offset:K, value:V ) : Void;
+	function offsetUnset( offset:K ) : Void;
+}

+ 835 - 0
std/php7/Boot.hx

@@ -0,0 +1,835 @@
+/*
+ * Copyright (C)2005-2016 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;
+	}
+
+	/**
+		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;
+	}
+
+	/**
+		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 (Syntax.instanceof(value, StdClass)) {
+				if (value.toString.isset() && 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 (Syntax.instanceof(value, HxClosure) || Syntax.instanceof(value, Closure)) {
+				return '<function>';
+			}
+			if (Syntax.instanceof(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() || left == null) && (right.is_string() || right == null || isNumber(right))) {
+			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':
+				return value.is_array();
+			case 'Enum', 'Class':
+				if (Syntax.instanceof(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 function isClass(value:Dynamic) : Bool {
+		return Syntax.instanceof(value, HxClass);
+	}
+
+	/**
+		Check if `value` is an enum constructor instance
+	**/
+	public static function isEnumValue(value:Dynamic) : Bool {
+		return Syntax.instanceof(value, HxEnum);
+	}
+
+	/**
+		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);
+	}
+}
+
+
+/**
+	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 + '::' + 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 = 0 ) : Int {
+		if (startIndex < 0) startIndex += str.length;
+		var index = Global.strpos(str, search, startIndex);
+		if (index == false) {
+			return -1;
+		} else {
+			return 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
+**/
+@:dox(hide)
+@:keep
+private class HxDynamicStr {
+	static var hxString : String = (cast HxString:HxClass).phpClassName;
+	var str : String;
+
+	/**
+		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;
+		}
+	}
+
+	function new( str:String ) {
+		this.str = str;
+	}
+
+	@:phpMagic
+	function __get( field:String ) : Dynamic {
+		switch (field) {
+			case 'length':      return str.length;
+			case 'toUpperCase': return HxString.toUpperCase.bind(str);
+			case 'toLowerCase': return HxString.toLowerCase.bind(str);
+			case 'charAt':      return HxString.charAt.bind(str);
+			case 'indexOf':     return HxString.indexOf.bind(str);
+			case 'lastIndexOf': return HxString.lastIndexOf.bind(str);
+			case 'split':       return HxString.split.bind(str);
+			case 'toString':    return HxString.toString.bind(str);
+			case 'substring':   return HxString.substring.bind(str);
+			case 'substr':      return HxString.substr.bind(str);
+			case 'charCodeAt':  return HxString.charCodeAt.bind(str);
+		}
+		/** Force invalid field access error */
+		return Syntax.getField(str, field);
+	}
+
+	@:phpMagic
+	function __call( method:String, args:NativeArray ) : Dynamic {
+		Global.array_unshift(args, str);
+		return Global.call_user_func_array(hxString + '::' + method, args);
+	}
+}
+
+
+/**
+	Anonymous objects implementation
+**/
+@:keep
+@:dox(hide)
+private class HxAnon extends StdClass {
+
+	public function new( fields:NativeArray = null ) {
+		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 (Syntax.instanceof(eThis, StdClass)) {
+			if (Syntax.instanceof(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));
+  }
+}

+ 12 - 0
std/php7/Closure.hx

@@ -0,0 +1,12 @@
+package php;
+
+import haxe.extern.Rest;
+
+/**
+    @see http://php.net/manual/en/class.closure.php
+**/
+@:native('Closure')
+extern class Closure {
+    public function bindTo( newthis:{}, newscope:Dynamic = "static" ) : Closure;
+    public function call ( newthis:{}, args:Rest<Dynamic> ) : Dynamic;
+}

+ 274 - 0
std/php7/Const.hx

@@ -0,0 +1,274 @@
+package php;
+
+/**
+	This class contains externs for native PHP constants defined in global namespace.
+	For native PHP functions in global namespace see `php.Global`.
+**/
+@:phpGlobal
+extern class Const {
+	/**
+		If this constant is defined and equals `true` then Haxe will not set error handler automatically.
+	**/
+	static var HAXE_CUSTOM_ERROR_HANDLER : Bool;
+	/**
+		@see http://php.net/manual/en/reserved.constants.php
+	**/
+	static var PHP_OS : String;
+	static var PHP_SAPI : String;
+	static var PHP_EOL : String;
+	static var PHP_INT_MAX : Int;
+	static var PHP_INT_MIN : Int;
+	static var PHP_INT_SIZE : Int;
+	/**
+		@see http://php.net/manual/en/language.constants.predefined.php
+	**/
+	static var __LINE__ : Int;
+	static var __FILE__ : String;
+	static var __DIR__ : String;
+	static var __FUNCTION__ : String;
+	static var __CLASS__ : String;
+	static var __TRAIT__ : String;
+	static var __METHOD__ : String;
+	static var __NAMESPACE__ : String;
+	/**
+		@see http://php.net/manual/en/errorfunc.constants.php
+	**/
+	static var E_ERROR : Int;
+	static var E_WARNING : Int;
+	static var E_PARSE : Int;
+	static var E_NOTICE : Int;
+	static var E_CORE_ERROR : Int;
+	static var E_CORE_WARNING : Int;
+	static var E_COMPILE_ERROR : Int;
+	static var E_COMPILE_WARNING : Int;
+	static var E_USER_ERROR : Int;
+	static var E_USER_WARNING : Int;
+	static var E_USER_NOTICE : Int;
+	static var E_STRICT : Int;
+	static var E_RECOVERABLE_ERROR : Int;
+	static var E_DEPRECATED : Int;
+	static var E_USER_DEPRECATED : Int;
+	static var E_ALL : Int;
+	/**
+		@see http://php.net/manual/en/function.count.php
+	**/
+	static var COUNT_NORMAL : Int;
+	static var COUNT_RECURSIVE : Int;
+	/**
+		@see http://php.net/manual/en/function.array-filter.php
+	**/
+	static var ARRAY_FILTER_USE_KEY : Int;
+	static var ARRAY_FILTER_USE_BOTH : Int;
+	/**
+		@see http://php.net/manual/en/function.debug-backtrace.php
+	**/
+	static var DEBUG_BACKTRACE_PROVIDE_OBJECT : Int;
+	static var DEBUG_BACKTRACE_IGNORE_ARGS : Int;
+	/**
+		@see http://php.net/manual/en/math.constants.php
+	**/
+	static var M_PI : Float;
+	static var M_E : Float;
+	static var M_LOG2E : Float;
+	static var M_LOG10E : Float;
+	static var M_LN2 : Float;
+	static var M_LN10 : Float;
+	static var M_PI_2 : Float;
+	static var M_PI_4 : Float;
+	static var M_1_PI : Float;
+	static var M_2_PI : Float;
+	static var M_SQRTPI : Float;
+	static var M_2_SQRTPI : Float;
+	static var M_SQRT2 : Float;
+	static var M_SQRT3 : Float;
+	static var M_SQRT1_2 : Float;
+	static var M_LNPI : Float;
+	static var M_EULER : Float;
+	static var PHP_ROUND_HALF_UP : Int;
+	static var PHP_ROUND_HALF_DOWN : Int;
+	static var PHP_ROUND_HALF_EVEN : Int;
+	static var PHP_ROUND_HALF_ODD : Int;
+	static var NAN : Float;
+	static var INF : Float;
+	/**
+		@see http://php.net/manual/en/function.setlocale.php
+	**/
+	static var LC_ALL : Int;
+	static var LC_COLLATE : Int;
+	static var LC_CTYPE : Int;
+	static var LC_MONETARY : Int;
+	static var LC_NUMERIC : Int;
+	static var LC_TIME : Int;
+	static var LC_MESSAGES : Int;
+	/**
+		@see http://php.net/manual/en/features.commandline.io-streams.php
+	**/
+	static var STDIN : Resource;
+	static var STDOUT : Resource;
+	static var STDERR : Resource;
+	/**
+		@see http://php.net/manual/en/function.preg-match-all.php
+	**/
+	static var PREG_PATTERN_ORDER : Int;
+	static var PREG_SET_ORDER : Int;
+	static var PREG_OFFSET_CAPTURE : Int;
+	/**
+		@see http://php.net/manual/en/function.preg-split.php
+	**/
+	static var PREG_SPLIT_NO_EMPTY : Int;
+	static var PREG_SPLIT_DELIM_CAPTURE : Int;
+	static var PREG_SPLIT_OFFSET_CAPTURE : Int;
+	/**
+		@see http://php.net/manual/en/function.htmlspecialchars.php
+	**/
+	static var ENT_COMPAT : Int;
+	static var ENT_QUOTES : Int;
+	static var ENT_NOQUOTES : Int;
+	static var ENT_IGNORE : Int;
+	static var ENT_SUBSTITUTE : Int;
+	static var ENT_DISALLOWED : Int;
+	static var ENT_HTML401 : Int;
+	static var ENT_XML1 : Int;
+	static var ENT_XHTML : Int;
+	static var ENT_HTML5 : Int;
+	/**
+		@see http://php.net/manual/en/function.str-pad.php
+	**/
+	static var STR_PAD_RIGHT : Int;
+	static var STR_PAD_LEFT : Int;
+	static var STR_PAD_BOTH : Int;
+	/**
+		@see http://php.net/manual/en/json.constants.php
+	**/
+	static var JSON_ERROR_NONE : Int;
+	static var JSON_ERROR_DEPTH : Int;
+	static var JSON_ERROR_STATE_MISMATCH : Int;
+	static var JSON_ERROR_CTRL_CHAR : Int;
+	static var JSON_ERROR_SYNTAX : Int;
+	static var JSON_ERROR_UTF8 : Int;
+	static var JSON_ERROR_RECURSION : Int;
+	static var JSON_ERROR_INF_OR_NAN : Int;
+	static var JSON_ERROR_UNSUPPORTED_TYPE : Int;
+	static var JSON_HEX_TAG : Int;
+	static var JSON_HEX_AMP : Int;
+	static var JSON_HEX_APOS : Int;
+	static var JSON_HEX_QUOT : Int;
+	static var JSON_FORCE_OBJECT : Int;
+	static var JSON_NUMERIC_CHECK : Int;
+	static var JSON_BIGINT_AS_STRING : Int;
+	static var JSON_PRETTY_PRINT : Int;
+	static var JSON_UNESCAPED_SLASHES : Int;
+	static var JSON_UNESCAPED_UNICODE : Int;
+	static var JSON_PARTIAL_OUTPUT_ON_ERROR : Int;
+	static var JSON_PRESERVE_ZERO_FRACTION : Int;
+	/**
+		@see http://php.net/manual/en/mysqli.constants.php
+	**/
+	static var MYSQLI_READ_DEFAULT_GROUP : Int;
+	static var MYSQLI_READ_DEFAULT_FILE : Int;
+	static var MYSQLI_OPT_CONNECT_TIMEOUT : Int;
+	static var MYSQLI_OPT_LOCAL_INFILE : Int;
+	static var MYSQLI_INIT_COMMAND : Int;
+	static var MYSQLI_CLIENT_SSL : Int;
+	static var MYSQLI_CLIENT_COMPRESS : Int;
+	static var MYSQLI_CLIENT_INTERACTIVE : Int;
+	static var MYSQLI_CLIENT_IGNORE_SPACE : Int;
+	static var MYSQLI_CLIENT_NO_SCHEMA : Int;
+	static var MYSQLI_CLIENT_MULTI_QUERIES : Int;
+	static var MYSQLI_STORE_RESULT : Int;
+	static var MYSQLI_USE_RESULT : Int;
+	static var MYSQLI_ASSOC : Int;
+	static var MYSQLI_NUM : Int;
+	static var MYSQLI_BOTH : Int;
+	static var MYSQLI_NOT_NULL_FLAG : Int;
+	static var MYSQLI_PRI_KEY_FLAG : Int;
+	static var MYSQLI_UNIQUE_KEY_FLAG : Int;
+	static var MYSQLI_MULTIPLE_KEY_FLAG : Int;
+	static var MYSQLI_BLOB_FLAG : Int;
+	static var MYSQLI_UNSIGNED_FLAG : Int;
+	static var MYSQLI_ZEROFILL_FLAG : Int;
+	static var MYSQLI_AUTO_INCREMENT_FLAG : Int;
+	static var MYSQLI_TIMESTAMP_FLAG : Int;
+	static var MYSQLI_SET_FLAG : Int;
+	static var MYSQLI_NUM_FLAG : Int;
+	static var MYSQLI_PART_KEY_FLAG : Int;
+	static var MYSQLI_GROUP_FLAG : Int;
+	static var MYSQLI_TYPE_DECIMAL : Int;
+	static var MYSQLI_TYPE_NEWDECIMAL : Int;
+	static var MYSQLI_TYPE_BIT : Int;
+	static var MYSQLI_TYPE_TINY : Int;
+	static var MYSQLI_TYPE_SHORT : Int;
+	static var MYSQLI_TYPE_LONG : Int;
+	static var MYSQLI_TYPE_FLOAT : Int;
+	static var MYSQLI_TYPE_DOUBLE : Int;
+	static var MYSQLI_TYPE_NULL : Int;
+	static var MYSQLI_TYPE_TIMESTAMP : Int;
+	static var MYSQLI_TYPE_LONGLONG : Int;
+	static var MYSQLI_TYPE_INT24 : Int;
+	static var MYSQLI_TYPE_DATE : Int;
+	static var MYSQLI_TYPE_TIME : Int;
+	static var MYSQLI_TYPE_DATETIME : Int;
+	static var MYSQLI_TYPE_YEAR : Int;
+	static var MYSQLI_TYPE_NEWDATE : Int;
+	static var MYSQLI_TYPE_INTERVAL : Int;
+	static var MYSQLI_TYPE_ENUM : Int;
+	static var MYSQLI_TYPE_SET : Int;
+	static var MYSQLI_TYPE_TINY_BLOB : Int;
+	static var MYSQLI_TYPE_MEDIUM_BLOB : Int;
+	static var MYSQLI_TYPE_LONG_BLOB : Int;
+	static var MYSQLI_TYPE_BLOB : Int;
+	static var MYSQLI_TYPE_VAR_STRING : Int;
+	static var MYSQLI_TYPE_STRING : Int;
+	static var MYSQLI_TYPE_CHAR : Int;
+	static var MYSQLI_TYPE_GEOMETRY : Int;
+	static var MYSQLI_NEED_DATA : Int;
+	static var MYSQLI_NO_DATA : Int;
+	static var MYSQLI_DATA_TRUNCATED : Int;
+	static var MYSQLI_ENUM_FLAG : Int;
+	static var MYSQLI_BINARY_FLAG : Int;
+	static var MYSQLI_CURSOR_TYPE_FOR_UPDATE : Int;
+	static var MYSQLI_CURSOR_TYPE_NO_CURSOR : Int;
+	static var MYSQLI_CURSOR_TYPE_READ_ONLY : Int;
+	static var MYSQLI_CURSOR_TYPE_SCROLLABLE : Int;
+	static var MYSQLI_STMT_ATTR_CURSOR_TYPE : Int;
+	static var MYSQLI_STMT_ATTR_PREFETCH_ROWS : Int;
+	static var MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH : Int;
+	static var MYSQLI_SET_CHARSET_NAME : Int;
+	static var MYSQLI_REPORT_INDEX : Int;
+	static var MYSQLI_REPORT_ERROR : Int;
+	static var MYSQLI_REPORT_STRICT : Int;
+	static var MYSQLI_REPORT_ALL : Int;
+	static var MYSQLI_REPORT_OFF : Int;
+	static var MYSQLI_DEBUG_TRACE_ENABLED : Int;
+	static var MYSQLI_SERVER_QUERY_NO_GOOD_INDEX_USED : Int;
+	static var MYSQLI_SERVER_QUERY_NO_INDEX_USED : Int;
+	static var MYSQLI_REFRESH_GRANT : Int;
+	static var MYSQLI_REFRESH_LOG : Int;
+	static var MYSQLI_REFRESH_TABLES : Int;
+	static var MYSQLI_REFRESH_HOSTS : Int;
+	static var MYSQLI_REFRESH_STATUS : Int;
+	static var MYSQLI_REFRESH_THREADS : Int;
+	static var MYSQLI_REFRESH_SLAVE : Int;
+	static var MYSQLI_REFRESH_MASTER : Int;
+	static var MYSQLI_TRANS_COR_AND_CHAIN : Int;
+	static var MYSQLI_TRANS_COR_AND_NO_CHAIN : Int;
+	static var MYSQLI_TRANS_COR_RELEASE : Int;
+	static var MYSQLI_TRANS_COR_NO_RELEASE : Int;
+	static var MYSQLI_TRANS_START_READ_ONLY : Int;
+	static var MYSQLI_TRANS_START_READ_WRITE : Int;
+	static var MYSQLI_TRANS_START_CONSISTENT_SNAPSHOT : Int;
+	/**
+		@see http://php.net/manual/en/sqlite3.constants.php
+	**/
+	static var SQLITE3_ASSOC : Int;
+	static var SQLITE3_NUM : Int;
+	static var SQLITE3_BOTH : Int;
+	static var SQLITE3_INTEGER : Int;
+	static var SQLITE3_FLOAT : Int;
+	static var SQLITE3_TEXT : Int;
+	static var SQLITE3_BLOB : Int;
+	static var SQLITE3_NULL : Int;
+	static var SQLITE3_OPEN_READONLY : Int;
+	static var SQLITE3_OPEN_READWRITE : Int;
+	static var SQLITE3_OPEN_CREATE : Int;
+}

+ 42 - 0
std/php7/Error.hx

@@ -0,0 +1,42 @@
+/*
+ * Copyright (C)2005-2016 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;
+
+@:native('Error')
+extern class Error implements Throwable {
+	function new(?message : String, ?code : Int, ?previous:Throwable) : Void;
+
+	private var message : String;
+	private var code : Int;
+	private var file : String;
+	private var line : Int;
+
+	@:final
+	function getPrevious() : Throwable;   // Returns previous Throwable
+	function getMessage() : String;       // message of the exception
+	function getCode() : Int;             // code of the exception
+	function getFile() : String;          // source filename
+	function getLine() : Int;             // source line
+	function getTrace() : NativeIndexedArray<NativeAssocArray<Dynamic>>;  // an array of the backtrace
+	function getTraceAsString() : String; // formated string of trace
+	@:phpMagic function __toString() : String;       // formated string for display
+}

+ 40 - 0
std/php7/ErrorException.hx

@@ -0,0 +1,40 @@
+/*
+ * Copyright (C)2005-2016 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;
+
+/**
+	@see http://php.net/manual/en/class.errorexception.php
+**/
+@:native('ErrorException')
+extern class ErrorException implements Throwable {
+	function new (?message:String, ?code:Int, ?severety:Int, ?filename:String, ?lineno:Int, ?previous:Throwable) : Void;
+
+	@:final function getSeverity() : Int;
+	@:final function getPrevious() : Throwable;   // Returns previous Throwable
+    @:final function getMessage() : String;       // message of the exception
+    @:final function getCode() : Int;             // code of the exception
+    @:final function getFile() : String;          // source filename
+    @:final function getLine() : Int;             // source line
+    @:final function getTrace() : NativeIndexedArray<NativeAssocArray<Dynamic>>;  // an array of the backtrace
+    @:final function getTraceAsString() : String; // formated string of trace
+	@:phpMagic function __toString() : String;       // formated string for display
+}

+ 42 - 0
std/php7/Exception.hx

@@ -0,0 +1,42 @@
+/*
+ * Copyright (C)2005-2016 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;
+
+@:native('Exception')
+extern class Exception implements Throwable {
+	public function new(?message : String, ?code : Int, ?previous:Throwable) : Void;
+
+	private var message : String;
+	private var code : Int;
+	private var file : String;
+	private var line : Int;
+
+	@:final
+	function getPrevious() : Throwable;   // Returns previous Throwable
+    function getMessage() : String;       // message of the exception
+    function getCode() : Int;             // code of the exception
+    function getFile() : String;          // source filename
+    function getLine() : Int;             // source line
+    function getTrace() : NativeIndexedArray<NativeAssocArray<Dynamic>>;  // an array of the backtrace
+    function getTraceAsString() : String; // formated string of trace
+	@:phpMagic function __toString() : String;       // formated string for display
+}

+ 938 - 0
std/php7/Global.hx

@@ -0,0 +1,938 @@
+package php;
+
+import haxe.extern.*;
+
+/**
+	This class contains externs for native PHP functions defined in global namespace.
+	For native PHP constants in global namespace see `php.Const`.
+**/
+@:phpGlobal
+extern class Global {
+	/**
+		@see http://php.net/manual/en/function.exit.php
+	**/
+	static function exit( status:EitherType<String,Int> ) : Void ;
+
+	/**
+		@see http://php.net/manual/en/function.exit.php
+	**/
+	static function die( status:EitherType<String,Int> ) : Void ;
+
+	/**
+		@see http://php.net/manual/en/function.error-reporting.php
+	**/
+	static function error_reporting( ?level:Int ) : Int ;
+
+	/**
+		@see http://php.net/manual/en/function.set-error-handler.php
+	**/
+	@:overload(function( error_handler:Int->String->Bool, ?error_types:Int ) : Dynamic {})
+	@:overload(function( error_handler:Int->String->String->Bool, ?error_types:Int ) : Dynamic {})
+	@:overload(function( error_handler:Int->String->String->Int->Bool, ?error_types:Int ) : Dynamic {})
+	static function set_error_handler( ?error_handler:Int->String->String->Int->Array<Dynamic>->Bool, ?error_types:Int ) : Dynamic ;
+
+	/**
+		@see http://php.net/manual/en/function.restore-error-handler.php
+	**/
+	static function restore_error_handler() : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.set-exception-handler.php
+	**/
+	static function set_exception_handler( exception_handler:Throwable->Void ) : Dynamic ;
+
+	/**
+		@see http://php.net/manual/en/function.restore-exception-handler.php
+	**/
+	static function restore_exception_handler() : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.is-int.php
+	**/
+	static function is_int( value:Dynamic ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.is-float.php
+	**/
+	static function is_float( value:Dynamic ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.is-string.php
+	**/
+	static function is_string( value:Dynamic ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.is-numeric.php
+	**/
+	static function is_numeric( value:Dynamic ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.is-bool.php
+	**/
+	static function is_bool( value:Dynamic ) : Bool ;
+
+	/**
+		Checks if `values` is `php.NativeArray`
+		@see http://php.net/manual/en/function.is-array.php
+	**/
+	static function is_array( value:Dynamic ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.is-object.php
+	**/
+	static function is_object( value:Dynamic ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.is-null.php
+	**/
+	static function is_null( value:Dynamic ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.is-subclass-of.php
+	**/
+	static function is_subclass_of( value:Dynamic, className:String, allow_string:Bool = true ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.class-exists.php
+	**/
+	static function class_exists( class_name:String, autoload:Bool = true ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.interface-exists.php
+	**/
+	static function interface_exists( interface_name:String, autoload:Bool = true ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.intval.php
+	**/
+	static function intval( value:Dynamic, base:Int = 10 ) : Int ;
+
+	/**
+		@see http://php.net/manual/en/function.floatval.php
+	**/
+	static function floatval( value:Dynamic ) : Float ;
+
+	/**
+		@see http://php.net/manual/en/function.boolval.php
+	**/
+	static function boolval( value:Dynamic ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.strval.php
+	**/
+	static function strval( value:Dynamic ) : String ;
+
+	/**
+		@see http://php.net/manual/en/function.phpversion.php
+	**/
+	static function phpversion( ?extension:String ) : String ;
+
+	/**
+		@see http://php.net/manual/en/function.class-alias.php
+	**/
+	static function class_alias( original:String, alias:String, autoload:Bool = true ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.count.php
+	**/
+	static function count( array:Dynamic, ?mode:Int ) : Int ;
+
+	/**
+		@see http://php.net/manual/en/function.array-filter.php
+	**/
+	@:overload(function(array:NativeArray,callback:Dynamic->Bool,?flag:Int):NativeArray {})
+	static function array_filter( array:NativeArray, ?callback:Dynamic->?Dynamic->Bool, flag:Int = 0 ) : NativeArray ;
+
+	/**
+		@see http://php.net/manual/en/function.implode.php
+	**/
+	@:overload(function(pieces:NativeArray):String {})
+	static function implode( glue:String, pieces:NativeArray ) : String ;
+
+	/**
+		@see http://php.net/manual/en/function.array-map.php
+	**/
+	static function array_map( callback:EitherType<Dynamic->Dynamic, String>, array:Rest<NativeArray> ) : NativeArray ;
+
+	/**
+		@see http://php.net/manual/en/function.array-merge.php
+	**/
+	static function array_merge( array:Rest<NativeArray> ) : NativeArray ;
+
+	/**
+		@see http://php.net/manual/en/function.array-diff.php
+	**/
+	static function array_diff( array:Rest<NativeArray> ) : NativeArray ;
+
+	/**
+		@see http://php.net/manual/en/function.array-pop.php
+	**/
+	static function array_pop( array:NativeArray ) : Dynamic;
+
+	/**
+		@see http://php.net/manual/en/function.array-push.php
+	**/
+	static function array_push( array:NativeArray, value:Rest<Dynamic> ) : Int ;
+
+	/**
+		@see http://php.net/manual/en/function.array-reverse.php
+	**/
+	static function array_reverse( array:NativeArray, preserve_keys:Bool = false ) : NativeArray ;
+
+	/**
+		@see http://php.net/manual/en/function.array-search.php
+	**/
+	static function array_search( needle:Dynamic, haystack:NativeArray, strict:Bool = false) : EitherType<Bool,EitherType<String,Int>> ;
+
+	/**
+		@see http://php.net/manual/en/function.array-shift.php
+	**/
+	static function array_shift( array:NativeArray ) : Dynamic ;
+
+	/**
+		@see http://php.net/manual/en/function.array-slice.php
+	**/
+	static function array_slice( array:NativeArray, offset:Int, length:Int = null, preserve_keys:Bool = false ) : NativeArray ;
+
+	/**
+		@see http://php.net/manual/en/function.array-splice.php
+	**/
+	static function array_splice( array:NativeArray, offset:Int, lenght:Int = 0, ?replacement:Dynamic ) : NativeArray ;
+
+	/**
+		@see http://php.net/manual/en/function.array-unshift.php
+	**/
+	static function array_unshift( arr:NativeArray, value:Rest<Dynamic> ) : Int ;
+
+	/**
+		@see http://php.net/manual/en/function.array-values.php
+	**/
+	static function array_values( arr:NativeArray ) : NativeIndexedArray<Dynamic> ;
+
+	/**
+		@see http://php.net/manual/en/function.array-keys.php
+	**/
+	static function array_keys( arr:NativeArray ) : NativeIndexedArray<EitherType<String,Int>> ;
+
+	/**
+		@see http://php.net/manual/en/function.array-key-exists.php
+	**/
+	static function array_key_exists( key:EitherType<String,Int>, arr:NativeArray ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.array-fill.php
+	**/
+	static function array_fill( start_index:Int, num:Int, value:Dynamic ) : NativeArray ;
+
+	/**
+		@see http://php.net/manual/en/function.in-array.php
+	**/
+	static function in_array( needle:Dynamic, haystack:NativeArray, strict:Bool = false ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.usort.php
+	**/
+	static function usort( array:NativeArray, value_compare_func:Dynamic->Dynamic->Int ) : Bool ;
+
+	/**
+		@see http://php.net/manual/en/function.reset.php
+	**/
+	static function reset( array:NativeArray ) : Dynamic;
+
+	/**
+		@see http://php.net/manual/en/function.current.php
+	**/
+	static function current( array:NativeArray ) : Dynamic;
+
+	/**
+		@see http://php.net/manual/en/function.next.php
+	**/
+	static function next( array:NativeArray ) : Dynamic;
+
+	/**
+		@see http://php.net/manual/en/function.prev.php
+	**/
+	static function prev( array:NativeArray ) : Dynamic;
+
+	/**
+		@see http://php.net/manual/en/function.end.php
+	**/
+	static function end( array:NativeArray ) : Dynamic;
+
+	/**
+		@see http://php.net/manual/en/function.key.php
+	**/
+	static function key( array:NativeArray ) : EitherType<String,Int>;
+
+	/**
+		@see http://php.net/manual/en/function.each.php
+	**/
+	static function each( array:NativeArray ) : NativeArray;
+
+	/**
+		@see http://php.net/manual/en/function.defined.php
+	**/
+	static function defined( name:String ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.define.php
+	**/
+	static function define( name:String, value:Dynamic, case_insensitive:Bool = false ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.echo.php
+	**/
+	static function echo( args:Rest<String> ) : Void;
+
+	/**
+		@see http://php.net/manual/en/function.method-exists.php
+	**/
+	static function method_exists( object:Dynamic, method_name:String ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.property-exists.php
+	**/
+	static function property_exists( object:Dynamic, property_name:String ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.is-callable.php
+	**/
+	static function is_callable( value:Dynamic,  syntax_only:Bool = false, ?callable_name:String ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.isset.php
+	**/
+	static function isset( value:Dynamic, args:Rest<Dynamic> ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.unset.php
+	**/
+	static function unset( value:Dynamic, values:Rest<Dynamic> ) : Void;
+
+	/**
+		@see http://php.net/manual/en/function.get-object-vars.php
+	**/
+	static function get_object_vars( object:{} ) : NativeAssocArray<Dynamic>;
+
+	/**
+		@see http://php.net/manual/en/function.get-class.php
+	**/
+	static function get_class( object:{} = null ) : EitherType<Bool,String>;
+
+	/**
+		@see http://php.net/manual/en/function.get-parent-class.php
+	**/
+	static function get_parent_class( ?object:Dynamic ) : EitherType<Bool,String>;
+
+	/**
+		@see http://php.net/manual/en/function.var-dump.php
+	**/
+	static function var_dump( args:Rest<Dynamic> ) : Void;
+
+	/**
+		@see http://php.net/manual/en/function.ord.php
+	**/
+	static function ord( string:String ) : Int;
+
+	/**
+		@see http://php.net/manual/en/function.chr.php
+	**/
+	static function chr( code:Int ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.strpos.php
+	**/
+	static function strpos( haystack:String, needle:String, offset:Int = 0 ) : EitherType<Bool, Int>;
+
+	/**
+		@see http://php.net/manual/en/function.strrpos.php
+	**/
+	static function strrpos( haystack:String, needle:String, offset:Int = 0 ) : EitherType<Bool, Int>;
+
+	/**
+		@see http://php.net/manual/en/function.str-split.php
+	**/
+	static function str_split( string:String, split_length:Int = 1 ) : EitherType<Bool,NativeIndexedArray<String>>;
+
+	/**
+		@see http://php.net/manual/en/function.strlen.php
+	**/
+	static function strlen( string:String ) : Int;
+
+	/**
+		@see http://php.net/manual/en/function.strcmp.php
+	**/
+	static function strcmp( str1:String, str2:String ) : Int;
+
+	/**
+		@see http://php.net/manual/en/function.str-repeat.php
+	**/
+	static function str_repeat( input:String, multiplier:Int ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.str-replace.php
+	**/
+	static function str_replace( search:EitherType<String,NativeArray>, replace:EitherType<String,NativeArray>, subject:EitherType<String,NativeArray>, ?count:Int ) : EitherType<String,NativeArray>;
+
+	/**
+		@see http://php.net/manual/en/function.explode.php
+	**/
+	static function explode( delimiter:String, string:String, ?limit:Int ) : EitherType<Bool,NativeIndexedArray<String>>;
+
+	/**
+		@see http://php.net/manual/en/function.substr.php
+	**/
+	static function substr( string:String, start:Int, ?length:Int ) : EitherType<Bool,String>;
+
+	/**
+		@see http://php.net/manual/en/function.substr_replace.php
+	**/
+	static function substr_replace( string:EitherType<String,NativeArray>, replacement:EitherType<String,NativeArray>, start:EitherType<Int,NativeArray>, ?length:EitherType<Int,NativeArray> ) : EitherType<String,NativeArray>;
+
+	/**
+		@see http://php.net/manual/en/function.strtoupper.php
+	**/
+	static function strtoupper( string:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.strtolower.php
+	**/
+	static function strtolower( string:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.debug-backtrace.php
+	**/
+	static function debug_backtrace( ?options:Int, ?limit:Int ) : NativeIndexedArray<NativeAssocArray<Dynamic>>;
+
+	/**
+		@see http://php.net/manual/en/function.call-user-func.php
+	**/
+	static function call_user_func( callback:Dynamic, arguments:Rest<Dynamic> ) : Dynamic;
+
+	/**
+		@see http://php.net/manual/en/function.call-user-func-array.php
+	**/
+	static function call_user_func_array( callback:Dynamic, arguments:NativeArray ) : Dynamic;
+
+	/**
+		@see http://php.net/manual/en/function.func-get-args.php
+	**/
+	static function func_get_args() : NativeIndexedArray<Dynamic>;
+
+	/**
+		@see http://php.net/manual/en/function.abs.php
+	**/
+	static function abs<T:Float>( number:T ) : T;
+
+	/**
+		@see http://php.net/manual/en/function.min.php
+	**/
+	static function min( values:Rest<Dynamic> ) : Dynamic;
+
+	/**
+		@see http://php.net/manual/en/function.max.php
+	**/
+	static function max( values:Rest<Dynamic> ) : Dynamic;
+
+	/**
+		@see http://php.net/manual/en/function.sin.php
+	**/
+	static function sin( arg:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.cos.php
+	**/
+	static function cos( arg:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.atan2.php
+	**/
+	static function atan2( y:Float, x:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.tan.php
+	**/
+	static function tan( arg:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.exp.php
+	**/
+	static function exp( arg:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.log.php
+	**/
+	static function log( arg:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.sqrt.php
+	**/
+	static function sqrt( arg:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.floor.php
+	**/
+	static function floor( arg:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.ceil.php
+	**/
+	static function ceil( arg:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.round.php
+	**/
+	static function round( val:Float, precision:Int = 0, ?mode:Int ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.atan.php
+	**/
+	static function atan( arg:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.asin.php
+	**/
+	static function asin( arg:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.acos.php
+	**/
+	static function acos( arg:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.pow.php
+	**/
+	static function pow( base:Float, exp:Float ) : Float;
+
+	/**
+		@see http://php.net/manual/en/function.mt-rand.php
+	**/
+	@:overload(function() : Int {})
+	static function mt_rand( base:Int, exp:Int ) : Int;
+
+	/**
+		@see http://php.net/manual/en/function.mt-getrandmax.php
+	**/
+	static function mt_getrandmax() : Int;
+
+	/**
+		@see http://php.net/manual/en/function.is-nan.php
+	**/
+	static function is_nan( arg:Float ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.is-finite.php
+	**/
+	static function is_finite( arg:Float ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.trim.php
+	**/
+	static function trim( str:String, ?character_mask:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.rtrim.php
+	**/
+	static function rtrim( str:String, ?character_mask:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.ltrim.php
+	**/
+	static function ltrim( str:String, ?character_mask:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.getenv.php
+	**/
+	static function getenv( varname:String ) : EitherType<String,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.putenv.php
+	**/
+	static function putenv( setting:String ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.sleep.php
+	**/
+	static function sleep( seconds:Int ) : EitherType<Bool,Int>;
+
+	/**
+		@see http://php.net/manual/en/function.usleep.php
+	**/
+	static function usleep( micro_seconds:Int ) : Void;
+
+	/**
+		@see http://php.net/manual/en/function.setlocale.php
+	**/
+	@:overload(function( category:Int, locale:NativeIndexedArray<String> ) : EitherType<Bool,String> {})
+	static function setlocale( category:Int, locale:Rest<String> ) : EitherType<Bool,String>;
+
+	/**
+		@see http://php.net/manual/en/function.getcwd.php
+	**/
+	static function getcwd() : EitherType<String,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.chdir.php
+	**/
+	static function chdir( directory:String ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.php-uname.php
+	**/
+	static function php_uname( mode:String = 'a' ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.system.php
+	**/
+	static function system( command:String, ?return_var:Ref<Int> ) : EitherType<String,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.microtime.php
+	**/
+	static function microtime( get_as_float:Bool = false ) : EitherType<Float,String>;
+
+	/**
+		@see http://php.net/manual/en/function.fopen.php
+	**/
+	static function fopen( filename:String, mode:String, use_include_path:Bool = false, ?context:Resource ) : EitherType<Bool,Resource>;
+
+	/**
+		@see http://php.net/manual/en/function.fclose.php
+	**/
+	static function fclose( handle:Resource ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.feof.php
+	**/
+	static function feof( handle:Resource ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.rewind.php
+	**/
+	static function rewind( handle:Resource ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.fgetc.php
+	**/
+	static function fgetc( handle:Resource ) : EitherType<Bool,String>;
+
+	/**
+		@see http://php.net/manual/en/function.fwrite.php
+	**/
+	static function fwrite( handle:Resource, string:String, ?length:Int ) : EitherType<Int,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.fread.php
+	**/
+	static function fread( handle:Resource, length:Int ) : EitherType<Bool,String>;
+
+	/**
+		@see http://php.net/manual/en/function.file-exists.php
+	**/
+	static function file_exists( filename:String ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.clearstatcache.php
+	**/
+	static function clearstatcache( clear_realpath_cache:Bool = false, ?filename:String ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.fstat.php
+	**/
+	static function fstat( handle:Resource ) : NativeArray;
+
+	/**
+		@see http://php.net/manual/en/function.stat.php
+	**/
+	static function stat( filename:String ) : EitherType<NativeArray,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.realpath.php
+	**/
+	static function realpath( path:String ) : EitherType<String,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.filetype.php
+	**/
+	static function filetype( filename:String ) : EitherType<String,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.mkdir.php
+	**/
+	static function mkdir( pathname:String, mode:Int = 511, recursive:Bool = false, ?context:Resource ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.unlink.php
+	**/
+	static function unlink( filename:String, ?context:Resource ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.rmdir.php
+	**/
+	static function rmdir( dirname:String, ?context:Resource ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.dirname.php
+	**/
+	static function dirname( path:String, levels:Int = 1 ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.opendir.php
+	**/
+	static function opendir( path:String, ?context:Resource ) : EitherType<Resource,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.closedir.php
+	**/
+	static function closedir( dir_handle:Resource ) : Void;
+
+	/**
+		@see http://php.net/manual/en/function.readdir.php
+	**/
+	static function readdir( ?dir_handle:Resource ) : EitherType<String,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.rewinddir.php
+	**/
+	static function rewinddir( ?dir_handle:Resource ) : Void;
+
+	/**
+		@see http://php.net/manual/en/function.is-dir.php
+	**/
+	static function is_dir( filename:String ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.rename.php
+	**/
+	static function rename( oldname:String, newname:String, ?context:Resource ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.preg-match.php
+	**/
+	static function preg_match( pattern:String, subject:String, ?matches:NativeArray, ?flags:Int, ?offset:Int ) : EitherType<Bool,Int> ;
+
+	/**
+		@see http://php.net/manual/en/function.preg-match-all.php
+	**/
+	static function preg_match_all( pattern:String, subject:String, ?matches:NativeArray, ?flags:Int, ?offset:Int ) : EitherType<Bool,Int> ;
+
+	/**
+		@see http://php.net/manual/en/function.preg-split.php
+	**/
+	static function preg_split( pattern:String, subject:String, limit:Int = -1, flags:Int = 0 ) : EitherType<Bool,NativeArray> ;
+
+	/**
+		@see http://php.net/manual/en/function.preg-replace.php
+	**/
+	static function preg_replace( pattern:EitherType<String,NativeArray>, replacement:EitherType<String,NativeArray>, subject:EitherType<String,NativeArray>, limit:Int = -1, ?count:Int ) : EitherType<String,NativeArray> ;
+
+	/**
+		@see http://php.net/manual/en/function.md5.php
+	**/
+	static function md5( str:String, raw_output:Bool = false ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.sha1.php
+	**/
+	static function sha1( str:String, raw_output:Bool = false ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.hash.php
+	**/
+	static function hash( algo:String, str:String, raw_output:Bool = false ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.pack.php
+	**/
+	static function pack( format:String, args:Rest<Dynamic> ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.unpack.php
+	**/
+	static function unpack( format:String, data:String ) : NativeArray;
+
+	/**
+		@see http://php.net/manual/en/function.chunk-split.php
+	**/
+	static function chunk_split( body:String, chunklen:Int = 76, end:String = "\r\n" ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.urlencode.php
+	**/
+	static function urlencode( str:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.urldecode.php
+	**/
+	static function urldecode( str:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.rawurlencode.php
+	**/
+	static function rawurlencode( str:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.rawurldecode.php
+	**/
+	static function rawurldecode( str:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.htmlspecialchars.php
+	**/
+	static function htmlspecialchars( string:String, ?flags:Int, ?encoding:String, double_encode:Bool = true ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.htmlspecialchars_decode.php
+	**/
+	static function htmlspecialchars_decode( string:String, ?flags:Int ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.str-pad.php
+	**/
+	static function str_pad( input:String, pad_length:Int, pad_String:String = ' ', ?pad_type:Int ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.dechex.php
+	**/
+	static function dechex( number:Int ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.hexdec.php
+	**/
+	static function hexdec( hex_string:String ) : Int;
+
+	/**
+		@see http://php.net/manual/en/function.serialize.php
+	**/
+	static function serialize( value:Dynamic ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.unserialize.php
+	**/
+	static function unserialize( str:String, ?options:NativeArray ) : Dynamic;
+
+	/**
+		@see http://php.net/manual/en/function.extension-loaded.php
+	**/
+	static function extension_loaded( name:String ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.strncasecmp.php
+	**/
+	static function strncasecmp( str1:String, str2:String, len:Int ) : Int;
+
+	/**
+		@see http://php.net/manual/en/function.strcasecmp.php
+	**/
+	static function strcasecmp( str1:String, str2:String ) : Int;
+
+	/**
+		@see http://php.net/manual/en/function.fpassthru.php
+	**/
+	static function fpassthru( handle:Resource ) : Int;
+
+	/**
+		@see http://php.net/manual/en/function.json-encode.php
+	**/
+	static function json_encode( value:Dynamic, options:Int = 0, depth:Int = 512 ) : EitherType<String,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.json-decode.php
+	**/
+	static function json_decode( json:String, assoc:Bool = false, depth:Int = 512, options:Int = 512 ) : Dynamic;
+
+	/**
+		@see http://php.net/manual/en/function.json-last-error.php
+	**/
+	static function json_last_error() : Int;
+
+	/**
+		@see http://php.net/manual/en/function.json-last-error-msg.php
+	**/
+	static function json_last_error_msg() : EitherType<String,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.spl-object-hash.php
+	**/
+	static function spl_object_hash( obj:{} ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.utf8-encode.php
+	**/
+	static function utf8_encode( data:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.utf8-decode.php
+	**/
+	static function utf8_decode( data:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.mb-convert-encoding.php
+	**/
+	static function mb_convert_encoding( str:String, to_encoding:String, ?from_encoding:Dynamic ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.mb-check-encoding.php
+	**/
+	static function mb_check_encoding( str:String = null, ?encoding:String ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.mb-strlen.php
+	**/
+	static function mb_strlen( str:String, ?encoding:String ) : EitherType<Int,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.mb-substr.php
+	**/
+	static function mb_substr( str:String, start:Int, length:Int = null, ?encoding:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.proc-open.php
+	**/
+	static function proc_open( cmd:String, descriptorspec:NativeArray, pipes:NativeIndexedArray<Resource>, ?cwd:String, ?env:NativeArray, ?other_options:NativeArray ) : EitherType<Resource,Bool>;
+
+	/**
+		@see http://php.net/manual/en/function.proc-get-status.php
+	**/
+	static function proc_get_status( process:Resource ) : EitherType<Bool,NativeAssocArray<Scalar>>;
+
+	/**
+		@see http://php.net/manual/en/function.proc-close.php
+	**/
+	static function proc_close( process:Resource ) : Int;
+
+	/**
+		@see http://php.net/manual/en/function.proc-terminate.php
+	**/
+	static function proc_terminate( process:Resource, signal:Int = 15 ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.stream-select.php
+	**/
+	static function stream_select( read:NativeArray, write:NativeArray, except:NativeArray, tv_sec:Int, tv_usec:Int = 0 ) : Bool;
+
+	/**
+		@see http://php.net/manual/en/function.ini-get.php
+	**/
+	static function ini_get( var_name:String ) : EitherType<Bool,String>;
+
+	/**
+		@see http://php.net/manual/en/function.ini-set.php
+	**/
+	static function ini_set( var_name:String, newvalue:String ) : EitherType<Bool,String>;
+
+	/**
+		@see http://php.net/manual/en/function.sqlite-error-string.php
+	**/
+	static function sqlite_error_string( error_code:Int ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.sqlite-escape-string.php
+	**/
+	static function sqlite_escape_string( item:String ) : String;
+
+	/**
+		@see http://php.net/manual/en/function.set-time-limit.php
+	**/
+	static function set_time_limit( seconds:Int ) : Bool;
+}

+ 32 - 0
std/php7/IteratorAggregate.hx

@@ -0,0 +1,32 @@
+/*
+ * Copyright (C)2005-2016 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;
+
+@:native('IteratorAggregate')
+extern interface IteratorAggregate<T> {
+	/**
+		This method is not public to not induce Haxe users to use it ;)
+		Use iterator() instead.
+		The return type would be Aggregator that is unusable in Haxe
+	**/
+	private function getIterator() : Iterator<T>; //
+}

+ 152 - 0
std/php7/Lib.hx

@@ -0,0 +1,152 @@
+/*
+ * Copyright (C)2005-2016 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.ds.StringMap;
+
+/**
+	Platform-specific PHP Library. Provides some platform-specific functions
+	for the PHP target, such as conversion from Haxe types to native types
+	and vice-versa.
+**/
+class Lib {
+	/**
+		Print the specified value on the default output.
+	**/
+	public static inline function print( v : Dynamic ) : Void {
+		Global.echo(Std.string(v));
+	}
+
+	/**
+		Print the specified value on the default output followed by
+		a newline character.
+	**/
+	public static function println( v : Dynamic ) : Void {
+		print(v);
+		print("\n");
+	}
+
+	/**
+		Displays structured information about one or more expressions
+		that includes its type and value. Arrays and objects are
+		explored recursively with values indented to show structure.
+	*/
+	public static inline function dump(v : Dynamic) : Void {
+		Global.var_dump(v);
+	}
+
+	/**
+		Serialize using native PHP serialization. This will return a binary
+		`String` that can be stored for long term usage.
+	**/
+	public static inline function serialize( v : Dynamic ) : String {
+		return Global.serialize(v);
+	}
+
+	/**
+		Unserialize a `String` using native PHP serialization. See `php.Lib.serialize()`.
+	**/
+	public static inline function unserialize( s : String ) : Dynamic {
+		return Global.unserialize(s);
+	}
+
+	/**
+		Find out whether an extension is loaded.
+	*/
+	public static inline function extensionLoaded(name : String) {
+		return Global.extension_loaded(name);
+	}
+
+	public static inline function isCli() : Bool {
+		return 0 == Global.strncasecmp(Const.PHP_SAPI, 'cli', 3);
+	}
+
+	/**
+		Output file content from the given file name.
+	*/
+	public static inline function printFile(file : String) {
+		return Global.fpassthru(Global.fopen(file,  "r"));
+	}
+
+	public static inline function toPhpArray(a : Array<Dynamic>) : NativeArray {
+		return @:privateAccess a.arr;
+	}
+
+	public static inline function toHaxeArray(a : NativeArray) : Array<Dynamic> {
+		return @:privateAccess Array.wrap(a);
+	}
+
+	public static function hashOfAssociativeArray<T>(arr : NativeAssocArray<T>) : Map<String,T> {
+		var result = new StringMap();
+		@:privateAccess result.data = arr;
+		return result;
+	}
+
+	public static inline function associativeArrayOfHash(hash : haxe.ds.StringMap<Dynamic>) : NativeArray {
+		return @:privateAccess hash.data;
+	}
+
+	public static inline function objectOfAssociativeArray(arr : NativeArray) : Dynamic {
+		return Boot.createAnon(arr);
+	}
+
+	public static inline function associativeArrayOfObject(ob : Dynamic) : NativeArray {
+		return Syntax.array(ob);
+	}
+
+	/**
+	 * See the documentation for the equivalent PHP function for details on usage:
+	 * <http://php.net/manual/en/function.mail.php>
+	 * @param	to
+	 * @param	subject
+	 * @param	message
+	 * @param	?additionalHeaders
+	 * @param	?additionalParameters
+	 */
+	public static function mail(to : String, subject : String, message : String, ?additionalHeaders : String, ?additionalParameters : String) : Bool
+	{
+		throw "Not implemented";
+	}
+
+	/**
+		For neko compatibility only.
+	**/
+	public static function rethrow( e : Dynamic ) {
+		throw "Not implemented";
+	}
+
+	static function appendType(o : Dynamic, path : Array<String>, t : Dynamic) {
+		throw "Not implemented";
+	}
+
+	public static function getClasses() {
+		throw "Not implemented";
+	}
+
+	/**
+	*  Loads types defined in the specified directory.
+ 	*/
+ 	public static function loadLib(pathToLib : String) : Void
+ 	{
+		throw "Not implemented";
+ 	}
+}

+ 67 - 0
std/php7/NativeArray.hx

@@ -0,0 +1,67 @@
+/*
+ * Copyright (C)2005-2016 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;
+
+using php.Global;
+
+/**
+	Native PHP array.
+**/
+@:coreType @:runtimeValue abstract NativeArray {
+	public inline function new()
+		this = Syntax.arrayDecl();
+
+	@:arrayAccess function getByInt(key:Int):Dynamic;
+	@:arrayAccess function setByInt(key:Int, val:Dynamic):Dynamic;
+	@:arrayAccess function getByFloat(key:Float):Dynamic;
+	@:arrayAccess function setByFloat(key:Float, val:Dynamic):Dynamic;
+	@:arrayAccess function getByString(key:String):Dynamic;
+	@:arrayAccess function setByString(key:String, val:Dynamic):Dynamic;
+	@:arrayAccess function getByBool(key:Bool):Dynamic;
+	@:arrayAccess function setByBool(key:Bool, val:Dynamic):Dynamic;
+
+	public inline function iterator()
+		return new NativeArrayIterator(this);
+}
+
+/**
+	Allows iterating over native PHP array with Haxe for-loop
+**/
+private class NativeArrayIterator {
+	var arr:NativeArray;
+	var hasMore:Bool;
+
+	public inline function new( a:NativeArray ) {
+		arr = a;
+		hasMore = (arr.reset() != false);
+	}
+
+	public inline function hasNext() : Bool {
+		return hasMore;
+	}
+
+	public inline function next() : Dynamic {
+		var result = arr.current();
+		hasMore = (arr.next() != false);
+		return result;
+	}
+}

+ 40 - 0
std/php7/NativeAssocArray.hx

@@ -0,0 +1,40 @@
+/*
+ * Copyright (C)2005-2016 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;
+
+@:forward
+abstract NativeAssocArray<T>(NativeArray) from NativeArray to NativeArray {
+	public inline function new()
+		this = Syntax.arrayDecl();
+
+	@:arrayAccess
+	inline function get(key:String):T
+		return this[key];
+
+	@:arrayAccess
+	inline function set(key:String, val:T):T
+		return this[key] = val;
+
+    //TODO
+    // @:to function toMap():Map<String,T>
+    // @:from static function fromMap<T>(map:Map<String,T>):NativeAssocArray<T>
+}

+ 44 - 0
std/php7/NativeIndexedArray.hx

@@ -0,0 +1,44 @@
+/*
+ * Copyright (C)2005-2016 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;
+
+@:forward
+abstract NativeIndexedArray<T>(NativeArray) from NativeArray to NativeArray {
+	public inline function new()
+		this = Syntax.arrayDecl();
+
+	@:arrayAccess
+	inline function get(idx:Int):T
+		return this[idx];
+
+	@:arrayAccess
+	inline function set(idx:Int, val:T):T
+		return this[idx] = val;
+
+	@:to
+	inline function toHaxeArray():Array<T>
+		return @:privateAccess Array.wrap(this);
+
+	@:from
+	static inline function fromHaxeArray<T>(a:Array<T>):NativeIndexedArray<T>
+		return @:privateAccess a.arr;
+}

+ 31 - 0
std/php7/NativeString.hx

@@ -0,0 +1,31 @@
+/*
+ * Copyright (C)2005-2016 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;
+
+/**
+	Native PHP string.
+**/
+@:coreType @:runtimeValue abstract NativeString from String to String {
+
+	@:arrayAccess function get(key:Int):String;
+	@:arrayAccess function set(key:Int, val:String):String;
+}

+ 9 - 0
std/php7/Ref.hx

@@ -0,0 +1,9 @@
+package php;
+
+/**
+    Special type which allows passing function arguments by reference.
+    This type should be used for externs only.
+**/
+abstract Ref<T>(T) from T to T {
+
+}

+ 7 - 0
std/php7/Resource.hx

@@ -0,0 +1,7 @@
+package php;
+
+import sys.io.File.FileHandle;
+
+abstract Resource(Dynamic) to FileHandle {
+
+}

+ 4 - 0
std/php7/RuntimeException.hx

@@ -0,0 +1,4 @@
+package php;
+
+@:native('RuntimeException')
+extern class RuntimeException extends Exception {}

+ 9 - 0
std/php7/Scalar.hx

@@ -0,0 +1,9 @@
+package php;
+
+import haxe.extern.EitherType;
+
+
+/**
+    `Scalar` is a type that is compatible with any scalar value (int, float, bool, string)
+**/
+typedef Scalar = EitherType<Int, EitherType<String, EitherType<Float, Bool>>>;

+ 168 - 0
std/php7/Session.hx

@@ -0,0 +1,168 @@
+/*
+ * Copyright (C)2005-2016 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;
+
+/**
+	Session consists of a way to preserve certain data across
+	subsequent accesses.
+*/
+class Session {
+	public static function getCacheLimiter() {
+		switch(untyped __call__("session_cache_limiter")) {
+			case "public":
+				return Public;
+			case "private":
+				return Private;
+			case "nocache":
+				return NoCache;
+			case "private_no_expire":
+				return PrivateNoExpire;
+		}
+		return null;
+	}
+
+	public static function setCacheLimiter(l : CacheLimiter) {
+		if(started) throw "You can't set the cache limiter while the session is already in use";
+		switch(l) {
+			case Public:
+				untyped __call__("session_cache_limiter", "public");
+			case Private:
+				untyped __call__("session_cache_limiter", "private");
+			case NoCache:
+				untyped __call__("session_cache_limiter", "nocache");
+			case PrivateNoExpire:
+				untyped __call__("session_cache_limiter", "private_no_expire");
+		}
+	}
+
+	public static function getCacheExpire() : Int {
+		return untyped __call__("session_cache_expire");
+	}
+
+	public static function setCacheExpire(minutes : Int) {
+		if(started) throw "You can't set the cache expire time while the session is already in use";
+		untyped __call__("session_cache_expire", minutes);
+	}
+
+	public static function setName(name : String) {
+		if(started) throw "You can't set the name while the session is already in use";
+		untyped __call__("session_name", name);
+	}
+
+	public static function getName() : String {
+		return untyped __call__("session_name");
+	}
+
+	public static function getId() : String {
+		return untyped __call__("session_id");
+	}
+
+	public static function setId(id : String) {
+		if(started) throw "You can't set the session id while the session is already in use";
+		untyped __call__("session_id", id);
+	}
+
+	public static function getSavePath() : String {
+		return untyped __call__("session_save_path");
+	}
+
+	public static function setSavePath(path : String) {
+		if(started) throw "You can't set the save path while the session is already in use";
+		untyped __call__("session_save_path", path);
+	}
+
+	public static function getModule() : String {
+		return untyped __call__("session_module_name");
+	}
+
+	public static function setModule(module : String) {
+		if(started) throw "You can't set the module while the session is already in use";
+		untyped __call__("session_module_name", module);
+	}
+
+	public static function regenerateId(?deleteold : Bool) : Bool {
+		return untyped __call__("session_regenerate_id", deleteold);
+	}
+
+	public static function get(name : String) : Dynamic {
+		start();
+		if(!untyped __call__('isset', __var__("_SESSION", name))) return null;
+		return untyped __var__("_SESSION", name);
+	}
+
+	public static function set(name : String, value : Dynamic) {
+		start();
+		return untyped __set__("_SESSION", name, value);
+	}
+
+	public static function setCookieParams(?lifetime : Int, ?path : String, ?domain : String, ?secure : Bool, ?httponly : Bool) {
+		if(started) throw "You can't set the cookie params while the session is already in use";
+		untyped __call__("session_set_cookie_params", lifetime, path, domain, secure, httponly);
+	}
+
+	public static function getCookieParams() : { lifetime : Int, path : String, domain : String, secure : Bool, httponly : Bool} {
+		return untyped __call__("_hx_anonymous", untyped __call__("session_get_cookie_params"));
+	}
+
+	// TODO: completely untested
+	public static function setSaveHandler(open : String -> String -> Bool, close : Void -> Bool, read : String -> String, write : String -> String -> Bool, destroy, gc) : Bool {
+		return untyped __call__("session_set_save_handler", open, close, read, write, destroy, gc);
+	}
+
+	public static function exists(name : String) {
+		start();
+		return untyped __call__("array_key_exists", name, __var__("_SESSION"));
+	}
+
+	public static function remove(name : String) {
+		start();
+		untyped __call__("unset", __var__("_SESSION", name));
+	}
+
+	public static var started(default, null) : Bool;
+	public static function start() {
+		if(started) return;
+		started = true;
+		untyped __call__("session_start");
+	}
+
+	public static function clear() {
+		untyped __call__("session_unset");
+	}
+
+	public static function close() {
+		untyped __call__("session_write_close");
+		started = false; // TODO: not sure this useful; test if a closed session can be re-opened (I doubt)
+	}
+
+	static function __init__()
+	{
+		started = untyped __call__("isset", __var__("_SESSION"));
+	}
+}
+
+enum CacheLimiter {
+	Public;
+	Private;
+	NoCache;
+	PrivateNoExpire;
+}

+ 6 - 0
std/php7/StdClass.hx

@@ -0,0 +1,6 @@
+package php;
+
+@:native('StdClass')
+extern class StdClass implements Dynamic {
+
+}

+ 60 - 0
std/php7/SuperGlobal.hx

@@ -0,0 +1,60 @@
+package php;
+
+
+
+class SuperGlobal {
+    /**
+        @see http://php.net/manual/en/reserved.variables.globals.php
+    **/
+    public static var GLOBALS (get,never):NativeAssocArray<Dynamic>;
+    static inline function get_GLOBALS() return untyped __php__("$GLOBALS");
+
+    /**
+        @see http://php.net/manual/en/reserved.variables.server.php
+    **/
+    public static var _SERVER (get,never):NativeAssocArray<Dynamic>;
+    static inline function get__SERVER() return untyped __php__("$_SERVER");
+
+    /**
+        @see http://php.net/manual/en/reserved.variables.get.php
+    **/
+    public static var _GET (get,never):NativeAssocArray<Dynamic>;
+    static inline function get__GET() return untyped __php__("$_GET");
+
+    /**
+        @see http://php.net/manual/en/reserved.variables.post.php
+    **/
+    public static var _POST (get,never):NativeAssocArray<Dynamic>;
+    static inline function get__POST() return untyped __php__("$_POST");
+
+    /**
+        @see http://php.net/manual/en/reserved.variables.files.php
+    **/
+    public static var _FILES (get,never):NativeAssocArray<Dynamic>;
+    static inline function get__FILES() return untyped __php__("$_FILES");
+
+    /**
+        @see http://php.net/manual/en/reserved.variables.cookie.php
+    **/
+    public static var _COOKIE (get,never):NativeAssocArray<Dynamic>;
+    static inline function get__COOKIE() return untyped __php__("$_COOKIE");
+
+    /**
+        @see http://php.net/manual/en/reserved.variables.session.php
+    **/
+    public static var _SESSION (get,never):NativeAssocArray<Dynamic>;
+    static inline function get__SESSION() return untyped __php__("$_SESSION");
+
+    /**
+        @see http://php.net/manual/en/reserved.variables.request.php
+    **/
+    public static var _REQUEST (get,never):NativeAssocArray<Dynamic>;
+    static inline function get__REQUEST() return untyped __php__("$_REQUEST");
+
+    /**
+        @see http://php.net/manual/en/reserved.variables.env.php
+    **/
+    public static var _ENV (get,never):NativeAssocArray<Dynamic>;
+    static inline function get__ENV() return untyped __php__("$_ENV");
+
+}

+ 126 - 0
std/php7/Syntax.hx

@@ -0,0 +1,126 @@
+package php;
+
+import haxe.extern.Rest;
+import haxe.extern.AsVar;
+import haxe.extern.EitherType;
+
+/**
+    Special extern class to support PHP language specifics.
+    Don't use these functions unless you are really sure what you are doing.
+**/
+extern class Syntax {
+    /**
+        This method allows to force specified binary operation for `left` and `right` values.
+        `operator` must be a constant string like "+" or "==".
+    **/
+    static function binop( left:Dynamic, operator:String, right:Dynamic ) : Dynamic;
+
+    /**
+        Generates `(int)$value`
+    **/
+    static function int( value:Dynamic ) : Int;
+
+    /**
+        Generates `(float)$value`
+    **/
+    static function float( value:Dynamic ) : Float;
+
+    /**
+        Generates `(string)$value`
+    **/
+    static function string( value:Dynamic ) : String;
+
+    /**
+        Generates `(bool)$value`
+    **/
+    static function bool( value:Dynamic ) : Bool;
+
+    /**
+        Generates `(object)$value`
+    **/
+    static function object( value:Dynamic ) : Dynamic;
+
+    /**
+        Generates `(array)$value`
+    **/
+    static function array( value:Dynamic ) : NativeArray;
+
+    /**
+        Ggenerates `$value instanceof $phpClassName`.
+        `type` only accepts direct class names. That means `Type.resolveClass('MyClass')` is not allowed, but `MyClass` is.
+    **/
+    static function instanceof<V,C>( value:AsVar<V>,  type:AsVar<Class<C>> ) : Bool;
+
+    /**
+        ```
+        PHP.foreach(collection, function(key, value) trace(key, value));
+        ```
+        generates:
+        ```
+        foreach($collection as $key => $value) {
+            trace($key, $value);
+        }
+        ```
+    **/
+    static function foreach<TCollection,TKey,TValue>( collection:TCollection, body:TKey->TValue->Void ) : Void;
+
+    /**
+        Generates `new $className($arg1, ...$argN)`
+    **/
+    static function construct( className:AsVar<String>, args:Rest<Dynamic>) : Dynamic;
+
+    /**
+        Generates instance field access for reading on `object`
+    **/
+    static function getField<T>( object:AsVar<T>, fieldName:AsVar<String> ) : Dynamic;
+
+    /**
+        Generates instance field access for writing on `object`
+    **/
+    static function setField<T>( object:AsVar<T>, fieldName:AsVar<String>, value:Dynamic ) : Void;
+
+    /**
+        Generates static field access for reading on `className`
+    **/
+    static function getStaticField( className:AsVar<EitherType<Class<Dynamic>,String>>, fieldName:AsVar<String> ) : Dynamic;
+
+    /**
+        Generates static field access for writing on `object`
+    **/
+    static function setStaticField( object:AsVar<EitherType<Class<Dynamic>,String>>, fieldName:AsVar<String>, value:Dynamic ) : Void;
+
+    /**
+        Generates a call to instance method: `$object->{$methodName}(<args>)`
+    **/
+    static function call<T>( object:AsVar<T>, methodName:AsVar<String>, args:Rest<Dynamic> ) : Dynamic;
+    /**
+        Generates a call to static method: `$className::{$methodName}(<args>)`
+    **/
+    static function staticCall( className:AsVar<EitherType<Class<Dynamic>,String>>, methodName:AsVar<String>, args:Rest<Dynamic> ) : Dynamic;
+
+    /**
+        ```
+        PHP.arrayDecl(arg1, arg2, arg3);
+        ```
+        Generates native array declaration:
+        ```
+        [$arg1, $arg2, $arg3]
+        ```
+    **/
+    static function arrayDecl<T>( args:Rest<T> ) : NativeIndexedArray<T>;
+
+    /**
+        Don't let compiler to optimize away local var passed to this method.
+    **/
+    static function keepVar( localVar:Dynamic ) : Void;
+
+    /**
+        Adds `...` operator before `args`
+    **/
+    static function splat( args:EitherType<NativeArray, Traversable> ) : Rest<Dynamic>;
+
+    /**
+        Add errors suppression operator `@` before `expression`
+    **/
+    static function suppress<T>( expression:T ) : T;
+}

+ 16 - 0
std/php7/Throwable.hx

@@ -0,0 +1,16 @@
+package php;
+
+/**
+    @see http://php.net/manual/en/class.throwable.php
+**/
+@:native('Throwable')
+extern interface Throwable {
+    function getPrevious() : Throwable;   // Returns previous Throwable
+    function getMessage() : String;       // message of the exception
+    function getCode() : Int;             // code of the exception
+    function getFile() : String;          // source filename
+    function getLine() : Int;             // source line
+    function getTrace() : NativeIndexedArray<NativeAssocArray<Dynamic>>;  // an array of the backtrace
+    function getTraceAsString() : String; // formated string of trace
+	@:phpMagic function __toString() : String;       // formated string for display
+}

+ 7 - 0
std/php7/Traversable.hx

@@ -0,0 +1,7 @@
+package php;
+
+/**
+    @see http://php.net/manual/en/class.traversable.php
+**/
+@:native('Traversable')
+extern interface Traversable {}

+ 395 - 0
std/php7/Web.hx

@@ -0,0 +1,395 @@
+/*
+ * Copyright (C)2005-2016 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.io.Bytes;
+
+/**
+	This class is used for accessing the local Web server and the current
+	client request and informations.
+**/
+class Web {
+
+	/**
+		Returns the GET and POST parameters.
+	**/
+	public static function getParams() : Map<String,String> {
+		#if force_std_separator
+		var a : NativeArray = untyped __php__("$_POST");
+		if(untyped __call__("get_magic_quotes_gpc"))
+			untyped __php__("reset($a); while(list($k, $v) = each($a)) $a[$k] = stripslashes((string)$v)");
+		var h = Lib.hashOfAssociativeArray(a);
+		var params = getParamsString();
+		if( params == "" )
+			return h;
+		for( p in ~/[;&]/g.split(params) ) {
+			var a = p.split("=");
+			var n = a.shift();
+			h.set(StringTools.urlDecode(n),StringTools.urlDecode(a.join("=")));
+		}
+		return h;
+		#else
+		var a : NativeArray = untyped __php__("array_merge($_GET, $_POST)");
+		if(untyped __call__("get_magic_quotes_gpc"))
+			untyped __php__("reset($a); while(list($k, $v) = each($a)) $a[$k] = stripslashes((string)$v)");
+		return Lib.hashOfAssociativeArray(a);
+		#end
+	}
+
+	/**
+		Returns an Array of Strings built using GET / POST values.
+		If you have in your URL the parameters `a[]=foo;a[]=hello;a[5]=bar;a[3]=baz` then
+		`php.Web.getParamValues("a")` will return `["foo","hello",null,"baz",null,"bar"]`.
+	**/
+	public static function getParamValues( param : String ) : Array<String> {
+		var reg = new EReg("^"+param+"(\\[|%5B)([0-9]*?)(\\]|%5D)=(.*?)$", "");
+		var res = new Array<String>();
+		var explore = function(data:String){
+			if (data == null || data.length == 0)
+				return;
+			for (part in data.split("&")){
+				if (reg.match(part)){
+					var idx = reg.matched(2);
+					var val = StringTools.urlDecode(reg.matched(4));
+					if (idx == "")
+						res.push(val);
+					else
+						res[Std.parseInt(idx)] = val;
+				}
+			}
+		}
+		explore(StringTools.replace(getParamsString(), ";", "&"));
+		explore(getPostData());
+
+        if (res.length == 0) {
+            var post:haxe.ds.StringMap<Dynamic> = Lib.hashOfAssociativeArray(untyped __php__("$_POST"));
+            var data = post.get(param);
+            var k = 0, v = "";
+            if (untyped __call__("is_array", data)) {
+                untyped __php__(" reset($data); while(list($k, $v) = each($data)) { ");
+                res[k] = v;
+                untyped __php__(" } ");
+            }
+        }
+
+		if (res.length == 0)
+			return null;
+		return res;
+	}
+
+	/**
+		Returns the local server host name.
+	**/
+	public static inline function getHostName() : String {
+		return untyped __php__("$_SERVER['SERVER_NAME']");
+	}
+
+	/**
+		Surprisingly returns the client IP address.
+	**/
+	public static inline function getClientIP() : String {
+		return untyped __php__("$_SERVER['REMOTE_ADDR']");
+	}
+
+	/**
+		Returns the original request URL (before any server internal redirections).
+	**/
+	public static function getURI() : String {
+		var s : String = untyped __php__("$_SERVER['REQUEST_URI']");
+		return s.split("?")[0];
+	}
+
+	/**
+		Tell the client to redirect to the given url ("Location" header).
+	**/
+	public static function redirect( url : String ) {
+		untyped __call__('header', "Location: " + url);
+	}
+
+	/**
+		Set an output header value. If some data have been printed, the headers have
+		already been sent so this will raise an exception.
+	**/
+	public static inline function setHeader( h : String, v : String ) {
+		untyped __call__('header', h+": "+v);
+	}
+
+	/**
+		Set the HTTP return code. Same remark as `php.Web.setHeader()`.
+		See status code explanation here: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+	**/
+	public static function setReturnCode( r : Int ) {
+		var code : String;
+		switch(r) {
+			case 100: code = "100 Continue";
+			case 101: code = "101 Switching Protocols";
+			case 200: code = "200 OK";
+			case 201: code = "201 Created";
+			case 202: code = "202 Accepted";
+			case 203: code = "203 Non-Authoritative Information";
+			case 204: code = "204 No Content";
+			case 205: code = "205 Reset Content";
+			case 206: code = "206 Partial Content";
+			case 300: code = "300 Multiple Choices";
+			case 301: code = "301 Moved Permanently";
+			case 302: code = "302 Found";
+			case 303: code = "303 See Other";
+			case 304: code = "304 Not Modified";
+			case 305: code = "305 Use Proxy";
+			case 307: code = "307 Temporary Redirect";
+			case 400: code = "400 Bad Request";
+			case 401: code = "401 Unauthorized";
+			case 402: code = "402 Payment Required";
+			case 403: code = "403 Forbidden";
+			case 404: code = "404 Not Found";
+			case 405: code = "405 Method Not Allowed";
+			case 406: code = "406 Not Acceptable";
+			case 407: code = "407 Proxy Authentication Required";
+			case 408: code = "408 Request Timeout";
+			case 409: code = "409 Conflict";
+			case 410: code = "410 Gone";
+			case 411: code = "411 Length Required";
+			case 412: code = "412 Precondition Failed";
+			case 413: code = "413 Request Entity Too Large";
+			case 414: code = "414 Request-URI Too Long";
+			case 415: code = "415 Unsupported Media Type";
+			case 416: code = "416 Requested Range Not Satisfiable";
+			case 417: code = "417 Expectation Failed";
+			case 500: code = "500 Internal Server Error";
+			case 501: code = "501 Not Implemented";
+			case 502: code = "502 Bad Gateway";
+			case 503: code = "503 Service Unavailable";
+			case 504: code = "504 Gateway Timeout";
+			case 505: code = "505 HTTP Version Not Supported";
+			default: code = Std.string(r);
+		}
+		untyped __call__('header', "HTTP/1.1 " + code, true, r);
+	}
+
+	/**
+		Retrieve a client header value sent with the request.
+	**/
+	public static function getClientHeader( k : String ) : String {
+		//Remark : PHP puts all headers in uppercase and replaces - with _, we deal with that here
+		var k = StringTools.replace(k.toUpperCase(),"-","_");
+		for(i in getClientHeaders()) {
+			if(i.header == k)
+				return i.value;
+		}
+		return null;
+	}
+
+
+	private static var _client_headers : List<{header : String, value : String}>;
+	/**
+		Retrieve all the client headers.
+	**/
+	public static function getClientHeaders() {
+		if(_client_headers == null) {
+			_client_headers = new List();
+			var h = Lib.hashOfAssociativeArray(untyped __php__("$_SERVER"));
+			for(k in h.keys()) {
+				if(k.substr(0,5) == "HTTP_") {
+					_client_headers.add({ header : k.substr(5), value : h.get(k)});
+				// this is also a valid prefix (issue #1883)
+				} else if(k.substr(0,8) == "CONTENT_") {
+					_client_headers.add({ header : k, value : h.get(k)});
+				}
+			}
+		}
+		return _client_headers;
+	}
+
+	/**
+		Returns all the GET parameters `String`
+	**/
+	public static function getParamsString() : String {
+		if(untyped __call__("isset", __var__("_SERVER", "QUERY_STRING")))
+			return untyped __var__("_SERVER", "QUERY_STRING");
+		else
+			return "";
+	}
+
+	/**
+		Returns all the POST data. POST Data is always parsed as
+		being application/x-www-form-urlencoded and is stored into
+		the getParams hashtable. POST Data is maximimized to 256K
+		unless the content type is multipart/form-data. In that
+		case, you will have to use `php.Web.getMultipart()` or
+		`php.Web.parseMultipart()` methods.
+	**/
+	public static function getPostData() {
+		var h = untyped __call__("fopen", "php://input", "r");
+		var bsize = 8192;
+		var max = 32;
+		var data : String = null;
+		var counter = 0;
+		while (!untyped __call__("feof", h) && counter < max) {
+			data += untyped __call__("fread", h, bsize);
+			counter++;
+		}
+		untyped __call__("fclose", h);
+		return data;
+	}
+
+	/**
+		Returns an hashtable of all Cookies sent by the client.
+		Modifying the hashtable will not modify the cookie, use `php.Web.setCookie()`
+		instead.
+	**/
+	public static function getCookies():Map<String,String> {
+		return Lib.hashOfAssociativeArray(untyped __php__("$_COOKIE"));
+	}
+
+
+	/**
+		Set a Cookie value in the HTTP headers. Same remark as `php.Web.setHeader()`.
+	**/
+	public static function setCookie( key : String, value : String, ?expire: Date, ?domain: String, ?path: String, ?secure: Bool, ?httpOnly: Bool ) {
+		var t = expire == null ? 0 : Std.int(expire.getTime()/1000.0);
+		if(path == null) path = '/';
+		if(domain == null) domain = '';
+		if(secure == null) secure = false;
+		if(httpOnly == null) httpOnly = false;
+		untyped __call__("setcookie", key, value, t, path, domain, secure, httpOnly);
+	}
+
+	/**
+		Returns an object with the authorization sent by the client (Basic scheme only).
+	**/
+	public static function getAuthorization() : { user : String, pass : String } {
+		if(!untyped __php__("isset($_SERVER['PHP_AUTH_USER'])"))
+			return null;
+		return untyped {user: __php__("$_SERVER['PHP_AUTH_USER']"), pass: __php__("$_SERVER['PHP_AUTH_PW']")};
+	}
+
+	/**
+		Get the current script directory in the local filesystem.
+	**/
+	public static inline function getCwd() : String {
+		return untyped __php__("dirname($_SERVER[\"SCRIPT_FILENAME\"])") + "/";
+	}
+
+	/**
+		Get the multipart parameters as an hashtable. The data
+		cannot exceed the maximum size specified.
+	**/
+	public static function getMultipart( maxSize : Int ) : Map<String,String> {
+		var h = new haxe.ds.StringMap();
+		var buf : StringBuf = null;
+		var curname = null;
+		parseMultipart(function(p,_) {
+			if( curname != null )
+				h.set(curname,buf.toString());
+			curname = p;
+			buf = new StringBuf();
+			maxSize -= p.length;
+			if( maxSize < 0 )
+				throw "Maximum size reached";
+		}, function(str,pos,len) {
+			maxSize -= len;
+			if( maxSize < 0 )
+				throw "Maximum size reached";
+			buf.addSub(str.toString(),pos,len);
+		});
+		if( curname != null )
+			h.set(curname,buf.toString());
+		return h;
+	}
+
+	/**
+		Parse the multipart data. Call `onPart` when a new part is found
+		with the part name and the filename if present
+		and `onData` when some part data is readed. You can this way
+		directly save the data on hard drive in the case of a file upload.
+	**/
+	public static function parseMultipart( onPart : String -> String -> Void, onData : Bytes -> Int -> Int -> Void ) : Void {
+		var a : NativeArray = untyped __var__("_POST");
+		if(untyped __call__("get_magic_quotes_gpc"))
+			untyped __php__("reset($a); while(list($k, $v) = each($a)) $a[$k] = stripslashes((string)$v)");
+		var post = Lib.hashOfAssociativeArray(a);
+
+		for (key in post.keys())
+		{
+			onPart(key, "");
+			var v = post.get(key);
+			onData(Bytes.ofString(v), 0, untyped __call__("strlen", v));
+		}
+
+		if(!untyped __call__("isset", __php__("$_FILES"))) return;
+		var parts : Array<String> = untyped __call__("new _hx_array",__call__("array_keys", __php__("$_FILES")));
+		for(part in parts) {
+			var info : Dynamic = untyped __php__("$_FILES[$part]");
+			var tmp : String = untyped info['tmp_name'];
+			var file : String = untyped info['name'];
+			var err : Int = untyped info['error'];
+
+			if(err > 0) {
+				switch(err) {
+					case 1: throw "The uploaded file exceeds the max size of " + untyped __call__('ini_get', 'upload_max_filesize');
+					case 2: throw "The uploaded file exceeds the max file size directive specified in the HTML form (max is" + untyped __call__('ini_get', 'post_max_size') + ")";
+					case 3: throw "The uploaded file was only partially uploaded";
+					case 4: continue; // No file was uploaded
+					case 6: throw "Missing a temporary folder";
+					case 7: throw "Failed to write file to disk";
+					case 8: throw "File upload stopped by extension";
+				}
+			}
+			onPart(part, file);
+			if ("" != file)
+			{
+				var h = untyped __call__("fopen", tmp, "r");
+				var bsize = 8192;
+				while (!untyped __call__("feof", h)) {
+					var buf : String = untyped __call__("fread", h, bsize);
+					var size : Int = untyped __call__("strlen", buf);
+					onData(Bytes.ofString(buf), 0, size);
+				}
+				untyped __call__("fclose", h);
+			}
+		}
+	}
+
+	/**
+		Flush the data sent to the client. By default on Apache, outgoing data is buffered so
+		this can be useful for displaying some long operation progress.
+	**/
+	public static inline function flush() : Void {
+		untyped __call__("flush");
+	}
+
+	/**
+		Get the HTTP method used by the client.
+	**/
+	public static function getMethod() : String {
+		if(untyped __php__("isset($_SERVER['REQUEST_METHOD'])"))
+			return untyped __php__("$_SERVER['REQUEST_METHOD']");
+		else
+			return null;
+	}
+
+	public static var isModNeko(default,null) : Bool;
+
+	static function __init__() {
+		isModNeko = !php.Lib.isCli();
+	}
+}

+ 240 - 0
std/php7/_std/Array.hx

@@ -0,0 +1,240 @@
+/*
+ * Copyright (C)2005-2016 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.
+ */
+import php.*;
+
+using php.Global;
+
+@:coreApi
+@:final
+class Array<T> implements ArrayAccess<Int,T> {
+	public var length(default, null):Int;
+	var arr:NativeIndexedArray<T>;
+
+	public function new() {
+		arr = new NativeIndexedArray<T>();
+		length = 0;
+	}
+
+	public function concat(a:Array<T>):Array<T> {
+		return wrap(Global.array_merge(arr, a.arr));
+	}
+
+	public function copy():Array<T> {
+		return wrap(arr);
+	}
+
+	public function filter(f:T->Bool):Array<T> {
+		return wrap(Global.array_values(Global.array_filter(arr, f)));
+	}
+
+	public function indexOf(x:T, ?fromIndex:Int):Int {
+		if (fromIndex == null) {
+			var index = Global.array_search(x, arr, true);
+			if (index == false) {
+				return -1;
+			} else {
+				return index;
+			}
+		}
+		if (fromIndex < 0) fromIndex += length;
+		if (fromIndex < 0) fromIndex = 0;
+		while (fromIndex < length) {
+			if (arr[fromIndex] == x)
+				return fromIndex;
+			fromIndex++;
+		}
+		return -1;
+	}
+
+	public function insert(pos:Int, x:T):Void {
+		length++;
+		Global.array_splice(arr, pos, 0, Syntax.arrayDecl(x));
+	}
+
+	@:keep
+	public function iterator() : Iterator<T> {
+		return new ArrayIterator(this);
+	}
+
+	public function join(sep:String):String {
+		return Global.implode(sep, Global.array_map('strval', arr));
+	}
+
+	public function lastIndexOf(x:T, ?fromIndex:Int):Int {
+		if (fromIndex == null || fromIndex >= length) fromIndex = length - 1;
+		if (fromIndex < 0) fromIndex += length;
+		while (fromIndex >= 0) {
+			if (arr[fromIndex] == x)
+				return fromIndex;
+			fromIndex--;
+		}
+		return -1;
+	}
+
+	public function map<S>(f:T->S):Array<S> {
+		return wrap(Global.array_map(f, arr));
+	}
+
+	public function pop():Null<T> {
+		if (length > 0) length--;
+		return Global.array_pop(arr);
+	}
+
+	public function push(x:T):Int {
+		return length = Global.array_push(arr, x);
+	}
+
+	public function remove(x:T):Bool {
+		for (i in 0...length) {
+			if (arr[i] == x) {
+				Global.array_splice(arr, i, 1);
+				length--;
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public function reverse():Void {
+		arr = Global.array_reverse(arr);
+	}
+
+	public function shift():Null<T> {
+		if (length > 0) length--;
+		return Global.array_shift(arr);
+	}
+
+	public function slice(pos:Int, ?end:Int):Array<T> {
+		if (pos < 0) pos += length;
+		if (pos < 0) pos = 0;
+		if (end == null) {
+			return wrap(Global.array_slice(arr, pos));
+		} else {
+			if (end < 0) end += length;
+			if (end <= pos) {
+				return [];
+			} else {
+				return wrap(Global.array_slice(arr, pos, end - pos));
+			}
+		}
+	}
+
+	public function sort(f:T->T->Int):Void {
+		arr.usort(f);
+	}
+
+	public function splice(pos:Int, len:Int):Array<T> {
+		if (len < 0) return [];
+		var result = wrap(Global.array_splice(arr, pos, len));
+		length -= result.length;
+		return result;
+	}
+
+	public function unshift(x:T):Void {
+		length = Global.array_unshift(arr, x);
+	}
+
+	public function toString():String {
+		var strings = Syntax.arrayDecl();
+		Syntax.foreach(arr, function(index:Int, value:T) {
+			strings[index] = Boot.stringify(value);
+		});
+		return '[' + Global.implode(',', strings) + ']';
+	}
+
+	@:noCompletion
+	function offsetExists( offset:Int ) : Bool {
+		return offset < length;
+	}
+
+	@:noCompletion
+	function offsetGet( offset:Int ) : Ref<T> {
+		try {
+			return arr[offset];
+		} catch(e:Dynamic) {
+			return null;
+		}
+	}
+
+	@:noCompletion
+	function offsetSet( offset:Int, value:T ) : Void {
+		if (length <= offset) {
+			arr = Global.array_merge(arr, Global.array_fill(0, offset + 1 - length, null));
+			length = offset + 1;
+		}
+		arr[offset] = value;
+	}
+
+	@:noCompletion
+	function offsetUnset( offset:Int ) : Void {
+		if (offset >= 0 && offset < length ) {
+			Global.array_splice(arr, offset, 1);
+			length--;
+		}
+	}
+
+	static function wrap<T>(arr:NativeIndexedArray<T>):Array<T> {
+		var a = new Array();
+		a.arr = arr;
+		a.length = Global.count(arr);
+		return a;
+	}
+}
+
+private class ArrayIterator<T> {
+	var idx:Int;
+	var arr:Array<T>;
+
+	public inline function new(arr:Array<T>) {
+		this.arr = arr;
+		idx = 0;
+	}
+
+	public inline function hasNext():Bool {
+		return idx < arr.length;
+	}
+
+	public inline function next():T {
+		return arr[idx++];
+	}
+
+	@:keep
+	@:phpMagic
+	function __get(method:String) {
+		return switch(method) {
+			case 'hasNext', 'next': Boot.closure(this, method);
+			case _: null;
+		}
+	}
+}
+
+
+/**
+	This one is required for `Array`
+**/
+@:native('ArrayAccess')
+private extern interface ArrayAccess<K,V> {
+	private function offsetExists( offset:K ) : Bool;
+	private function offsetGet( offset:K ) : V;
+	private function offsetSet( offset:K, value:V ) : Void;
+	private function offsetUnset( offset:K ) : Void;
+}

+ 92 - 0
std/php7/_std/Date.hx

@@ -0,0 +1,92 @@
+/*
+ * Copyright (C)2005-2016 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.
+ */
+@:coreApi @:final class Date
+{
+	private var __t : Float;
+
+	public function new(year : Int, month : Int, day : Int, hour : Int, min : Int, sec : Int ) : Void {
+		__t = untyped __call__("mktime", hour, min, sec, month+1, day, year);
+	}
+
+	public function getTime() : Float {
+		return __t * 1000;
+	}
+
+	private function getPhpTime() : Float {
+		return __t;
+	}
+
+	public function getFullYear() : Int {
+		return untyped __call__("intval", __call__("date", "Y", this.__t));
+	}
+
+	public function getMonth() : Int {
+		var m : Int = untyped __call__("intval", __call__("date", "n", this.__t));
+		return -1 + m;
+	}
+
+	public function getDate() : Int {
+		return untyped __call__("intval", __call__("date", "j", this.__t));
+	}
+
+	public function getHours() : Int {
+		return untyped __call__("intval", __call__("date", "G", this.__t));
+	}
+
+	public function getMinutes() : Int {
+		return untyped __call__("intval", __call__("date", "i", this.__t));
+	}
+
+	public function getSeconds() : Int {
+		return untyped __call__("intval", __call__("date", "s", this.__t));
+	}
+
+	public function getDay() : Int {
+		return untyped __call__("intval", __call__("date", "w", this.__t));
+	}
+
+	public function toString():String {
+		return untyped __call__("date", "Y-m-d H:i:s", this.__t);
+	}
+
+	public static function now() : Date {
+		return fromPhpTime(untyped __call__("round", __call__("microtime", true), 3));
+	}
+
+	static function fromPhpTime( t : Float ) : Date {
+		var d = new Date(2000,1,1,0,0,0);
+		d.__t = t;
+		return d;
+	}
+
+	public static function fromTime( t : Float ) : Date {
+		var d = new Date(2000,1,1,0,0,0);
+		d.__t = t / 1000;
+		return d;
+	}
+
+	public static function fromString( s : String ) : Date {
+		return fromPhpTime(untyped __call__("strtotime", s));
+	}
+}
+
+

+ 137 - 0
std/php7/_std/EReg.hx

@@ -0,0 +1,137 @@
+/*
+ * Copyright (C)2005-2016 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.
+ */
+
+import haxe.extern.EitherType;
+import php.*;
+
+@:coreApi @:final class EReg {
+
+	var r : Dynamic;
+	var last : String;
+	var global : Bool;
+	var pattern : String;
+	var options : String;
+	var re : String;
+	var matches : NativeIndexedArray<NativeIndexedArray<EitherType<Int,String>>>;
+
+	public function new( r : String, opt : String ) : Void {
+		this.pattern = r;
+		var a = opt.split("g");
+		global = a.length > 1;
+		if (global) {
+			opt = a.join("");
+		}
+		this.options = opt;
+		this.re = '"' + Global.str_replace('"', '\\"', r) + '"' + opt;
+	}
+
+	public function match( s : String ) : Bool {
+		var p : Int = Global.preg_match(re, s, matches, Const.PREG_OFFSET_CAPTURE);
+
+		if (p > 0) {
+			last = s;
+		} else {
+			last = null;
+		}
+		return p > 0;
+	}
+
+	public function matched( n : Int ) : String {
+		if (matches == null ||  n < 0) throw "EReg::matched";
+		// we can't differenciate between optional groups at the end of a match
+		// that have not been matched and invalid groups
+		if (n >= Global.count(matches)) return null;
+		if ((matches[n][1]:Int) < 0) return null;
+		return matches[n][0];
+	}
+
+	public function matchedLeft() : String {
+		if (Global.count(matches) == 0) throw "No string matched";
+		return last.substr(0, matches[0][1]);
+	}
+
+	public function matchedRight() : String {
+		if (Global.count(matches) == 0) throw "No string matched";
+		var x : Int = (matches[0][1]:Int) + Global.strlen(matches[0][0]);
+		return last.substr(x);
+	}
+
+	public function matchedPos() : { pos : Int, len : Int } {
+		return {
+			pos : matches[0][1],
+			len : Global.strlen(matches[0][0])
+		};
+	}
+
+	public function matchSub( s : String, pos : Int, len : Int = -1):Bool {
+		var subject = len < 0 ? s : s.substr(0,pos + len);
+		var p : Int = Global.preg_match(re, subject, matches, Const.PREG_OFFSET_CAPTURE, pos);
+		if(p > 0) {
+			last = s;
+		}
+		else {
+			last = null;
+		}
+		return p > 0;
+	}
+
+	public function split( s : String ) : Array<String> {
+		var parts:NativeArray = Global.preg_split(re, s, (global ? -1 : 2));
+		return @:privateAccess Array.wrap(parts);
+	}
+
+	public function replace( s : String, by : String ) : String {
+		by = Global.str_replace("\\$", "\\\\$", by);
+		by = Global.str_replace("$$", "\\$", by);
+		if (!Global.preg_match('/\\\\([^?].*?\\\\)/', re)) {
+			by = Global.preg_replace('/\\$(\\d+)/', '\\$\\1', by);
+		}
+		return Global.preg_replace(re, by, s, global ? -1 : 1);
+	}
+
+	public function map( s : String, f : EReg -> String ) : String {
+		var offset = 0;
+		var buf = new StringBuf();
+		do {
+			if (offset >= s.length) {
+				break;
+			} else if (!matchSub(s, offset)) {
+				buf.add(s.substr(offset));
+				break;
+			}
+			var p = matchedPos();
+			buf.add(s.substr(offset, p.pos - offset));
+			buf.add(f(this));
+			if (p.len == 0) {
+				buf.add(s.substr(p.pos, 1));
+				offset = p.pos + 1;
+			}
+			else {
+				offset = p.pos + p.len;
+			}
+		} while (global);
+		if (!global && offset > 0 && offset < s.length) {
+			buf.add(s.substr(offset));
+		}
+		return buf.toString();
+	}
+}

+ 58 - 0
std/php7/_std/Math.hx

@@ -0,0 +1,58 @@
+/*
+ * Copyright (C)2005-2016 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.
+ */
+
+import php.Global;
+import php.Const;
+
+@:coreApi class Math {
+	public static var PI(default,null) : Float = Const.M_PI;
+	public static var NaN(default,null) : Float = Const.NAN;
+	public static var POSITIVE_INFINITY(default,null) : Float = Const.INF;
+	public static var NEGATIVE_INFINITY(default,null) : Float = -Const.INF;
+
+	public static inline function abs( v:Float ) : Float return Global.abs(v);
+	public static inline function min( a:Float, b:Float ) : Float return isNaN(a) ? NaN : Global.min(a, b);
+	public static inline function max( a:Float, b:Float ) : Float return isNaN(b) ? NaN : Global.max(a, b);
+	public static inline function sin( v:Float ) : Float return Global.sin(v);
+	public static inline function cos( v:Float ) : Float return Global.cos(v);
+	public static inline function atan2( y:Float, x:Float ) : Float return Global.atan2(y, x);
+	public static inline function tan( v:Float ) : Float return Global.tan(v);
+	public static inline function exp( v:Float ) : Float return Global.exp(v);
+	public static inline function log( v:Float ) : Float return Global.log(v);
+	public static inline function sqrt( v:Float ) : Float return Global.sqrt(v);
+	public static inline function round( v:Float ) : Int return untyped __call__("(int)floor", v + 0.5);
+	public static inline function floor( v:Float ) : Int return untyped __call__("(int)floor", v);
+	public static inline function ceil( v:Float ) : Int return untyped __call__("(int)ceil", v);
+	public static inline function atan( v:Float ) : Float return Global.atan(v);
+	public static inline function asin( v:Float ) : Float return Global.asin(v);
+	public static inline function acos( v:Float ) : Float return Global.acos(v);
+	public static inline function pow( v:Float, exp:Float ) : Float return Global.pow(v, exp);
+	public static inline function random() : Float return Global.mt_rand() / Global.mt_getrandmax();
+	public static inline function isNaN( f:Float ) : Bool return Global.is_nan(f);
+	public static inline function isFinite( f:Float ) : Bool return Global.is_finite(f);
+
+	public static inline function fround( v:Float ) : Float return Global.floor(v + 0.5);
+	public static inline function ffloor( v:Float ) : Float return Global.floor(v);
+	public static inline function fceil( v:Float ) : Float return Global.ceil(v);
+}
+
+

+ 179 - 0
std/php7/_std/Reflect.hx

@@ -0,0 +1,179 @@
+/*
+ * Copyright (C)2005-2016 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.
+ */
+
+import php.Boot;
+import php.Syntax;
+import php.Closure;
+import haxe.Constraints;
+
+using php.Global;
+
+@:coreApi class Reflect {
+
+	public static function hasField( o : Dynamic, field : String ) : Bool {
+		if (!o.is_object()) return false;
+		if (o.property_exists(field)) return true;
+
+		if (Syntax.instanceof(o, cast Boot.getHxClass())) {
+			if (Global.property_exists(o.phpClassName, field)) return true;
+			return Global.method_exists(o.phpClassName, field);
+		}
+
+		return false;
+	}
+
+	public static function field( o : Dynamic, field : String ) : Dynamic {
+		if (!o.is_object()) return null;
+
+		if (o.property_exists(field)) {
+			return Syntax.getField(o, field);
+		}
+		if (o.method_exists(field)) {
+			return Boot.closure(o, field);
+		}
+
+		if (Syntax.instanceof(o, cast Boot.getHxClass())) {
+			if (Global.property_exists(o.phpClassName, field)) {
+				return Syntax.getField(o, field);
+			}
+			if (Global.method_exists(o.phpClassName, field)) {
+				return Boot.closure(o.phpClassName, field);
+			}
+		}
+
+		return null;
+	}
+
+	public static function setField( o : Dynamic, field : String, value : Dynamic ) : Void {
+		Syntax.setField(o, field, value);
+	}
+
+	public static function getProperty( o : Dynamic, field : String ) : Dynamic {
+		if (o.is_object()) {
+			if (Boot.hasGetter(Global.get_class(o), field)) {
+				return Syntax.call(o, 'get_$field');
+			} else if (Global.method_exists(o, field)) {
+				return Boot.closure(o, field);
+			} else {
+				return Syntax.getField(o, field);
+			}
+		}
+		if (o.is_string() && field == 'length') {
+			return Global.strlen(o);
+		}
+		return null;
+	}
+
+	public static function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void {
+		if (o.is_object()) {
+			if (Boot.hasSetter(Global.get_class(o), field)) {
+				Syntax.call(o, 'set_$field', value);
+			} else {
+				Syntax.setField(o, field, value);
+			}
+		}
+	}
+
+	public static function callMethod( o : Dynamic, func : Function, args : Array<Dynamic> ) : Dynamic {
+		if (Syntax.instanceof(func, Closure)) {
+			if (o != null) {
+				func = cast cast(func, Closure).bindTo(o);
+			}
+			return Global.call_user_func_array(func, @:privateAccess args.arr);
+		} else {
+			return Boot.castClosure(func).callWith(o, @:privateAccess args.arr);
+		}
+	}
+
+	public static function fields( o : Dynamic ) : Array<String> {
+		if (Global.is_object(o)) {
+			return @:privateAccess Array.wrap(Global.get_object_vars(o).array_keys());
+		}
+		return [];
+	}
+
+	public static function isFunction( f : Dynamic ) : Bool {
+		if (Syntax.instanceof(f, Closure)) {
+			return true;
+		} else {
+			return Syntax.instanceof(f, cast Boot.closureHxClass());
+		}
+	}
+
+	public static function compare<T>( a : T, b : T ) : Int {
+		if (a == b) return 0;
+		if (Global.is_string(a)){
+			return Global.strcmp(cast a, cast b);
+		} else {
+			return ((cast a) > (cast b) ? 1 : -1);
+		}
+	}
+
+	public static function compareMethods( f1 : Dynamic, f2 : Dynamic ) : Bool {
+		var hxClosure : Class<Dynamic> = cast Boot.closureHxClass();
+		if (Syntax.instanceof(f1, hxClosure) && Syntax.instanceof(f2, hxClosure)) {
+			return f1.equals(f2);
+		} else {
+			return f1 == f2;
+		}
+	}
+
+	public static function isObject( v : Dynamic ) : Bool {
+		if (Boot.isEnumValue(v)) {
+			return false;
+		} else {
+			return v.is_object() || v.is_string();
+		}
+	}
+
+	public static inline function isEnumValue( v : Dynamic ) : Bool {
+		return Boot.isEnumValue(v);
+	}
+
+	public static function deleteField( o : Dynamic, field : String ) : Bool {
+		if (hasField(o, field)) {
+			untyped Global.unset(Syntax.getField(o, field));
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	public static function copy<T>( o : T ) : T {
+		if (Global.is_object(o)) {
+			var fields = Global.get_object_vars(cast o);
+			var hxAnon = Boot.getHxAnon().phpClassName;
+			return Syntax.construct(hxAnon, fields);
+		} else {
+			return null;
+		}
+	}
+
+	@:overload(function( f : Array<Dynamic> -> Void ) : Dynamic {})
+	public static function makeVarArgs( f : Array<Dynamic> -> Dynamic ) : Dynamic {
+		return function () {
+			return Global.call_user_func(f, @:privateAccess Array.wrap(Global.func_get_args()));
+		}
+	}
+
+
+}

+ 92 - 0
std/php7/_std/Std.hx

@@ -0,0 +1,92 @@
+import php.Boot;
+
+/*
+ * Copyright (C)2005-2016 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.
+ */
+
+import php.Global;
+import php.Const;
+@:keep
+@:coreApi class Std {
+
+	public static inline function is( v : Dynamic, t : Dynamic ) : Bool {
+		return Boot.is(v, t);
+	}
+
+	public static function instance<T:{},S:T>( value : T, c : Class<S> ) : S {
+		return Std.is(value, c) ? cast value : null;
+	}
+
+	public static function string( s : Dynamic ) : String {
+		return Boot.stringify(s);
+	}
+
+	public static inline function int( x : Float ) : Int {
+		return untyped __call__('(int)', x);
+	}
+
+	public static function parseInt( x : String ) : Null<Int> {
+		if (Global.is_numeric(x)) {
+			return Global.intval(x, 10);
+		} else {
+			x = Global.ltrim(x);
+			var firstCharIndex = (x.charAt(0) == '-' ? 1 : 0);
+			var firstCharCode = x.charCodeAt(firstCharIndex);
+			if (!isDigitCode(firstCharCode)) {
+				return null;
+			}
+			var secondChar = x.charAt(firstCharIndex + 1);
+			if (secondChar == 'x' || secondChar == 'X') {
+				return Global.intval(x, 0);
+			} else {
+				return Global.intval(x, 10);
+			}
+		}
+	}
+
+	public static function parseFloat( x : String ) : Float {
+		var result = Global.floatval(x);
+		if (result != 0) return result;
+
+		x = Global.ltrim(x);
+		var firstCharIndex = (x.charAt(0) == '-' ? 1 : 0);
+		var charCode = x.charCodeAt(firstCharIndex);
+
+		if (charCode == '.'.code) {
+			charCode = x.charCodeAt(firstCharIndex + 1);
+		}
+
+		if (isDigitCode(charCode)) {
+			return 0.0;
+		} else {
+			return Const.NAN;
+		}
+	}
+
+	public static function random( x : Int ) : Int {
+		return x <= 1 ? 0 : Global.mt_rand(0, x - 1);
+	}
+
+	static inline function isDigitCode( charCode:Null<Int> ) : Bool {
+		return charCode != null && charCode >= '0'.code && charCode <= '9'.code;
+	}
+
+}

+ 51 - 0
std/php7/_std/StringBuf.hx

@@ -0,0 +1,51 @@
+/*
+ * Copyright (C)2005-2016 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.
+ */
+@:coreApi class StringBuf {
+	private var b : String;
+
+	public var length(get,never) : Int;
+
+	public function new() : Void {
+		b = "";
+	}
+
+	inline function get_length() : Int {
+		return b.length;
+	}
+
+	public function add<T>( x : T ) : Void {
+		untyped if( __call__('is_null',x) ) x = cast 'null' else if( __call__('is_bool',x) ) x = cast (x?'true':'false');
+		b += x;
+	}
+
+	public inline function addSub( s : String, pos : Int, ?len : Int ) : Void {
+		b += s.substr(pos,len);
+	}
+
+	public inline function addChar( c : Int ) : Void {
+		b += String.fromCharCode(c);
+	}
+
+	public inline function toString() : String {
+		return b;
+	}
+}

+ 205 - 0
std/php7/_std/StringTools.hx

@@ -0,0 +1,205 @@
+/*
+ * Copyright (C)2005-2016 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.
+ */
+
+import php.*;
+
+@:coreApi class StringTools {
+
+	public inline static function urlEncode( s : String ) : String {
+		return Global.rawurlencode(s);
+	}
+
+	public inline static function urlDecode( s : String ) : String {
+		return Global.urldecode(s);
+	}
+
+	public inline static function htmlEscape( s : String, ?quotes : Bool ) : String {
+		return Global.htmlspecialchars(s, (quotes ? Const.ENT_QUOTES | Const.ENT_HTML401 : Const.ENT_NOQUOTES));
+	}
+
+	public inline static function htmlUnescape( s : String ) : String {
+		return Global.htmlspecialchars_decode(s, Const.ENT_QUOTES);
+	}
+
+	public static function startsWith( s : String, start : String ) : Bool {
+		return start == '' || Global.strpos(s, start) == 0;
+	}
+
+	public static function endsWith( s : String, end : String ) : Bool {
+		return end == '' || Global.substr(s, -end.length) == end;
+	}
+
+	public static function isSpace( s : String, pos : Int ) : Bool {
+		var c = s.charCodeAt( pos );
+		return (c >= 9 && c <= 13) || c == 32;
+	}
+
+	public inline static function ltrim( s : String ) : String {
+		return Global.ltrim(s);
+	}
+
+	public inline static function rtrim( s : String ) : String {
+		return Global.rtrim(s);
+	}
+
+	public inline static function trim( s : String ) : String {
+		return Global.trim(s);
+	}
+
+	public static function rpad( s : String, c : String, l : Int ) : String {
+		if (c.length == 0 || s.length >= l) return s;
+		var padLength = Math.ceil((l - s.length) / c.length) * c.length + s.length;
+		return Global.str_pad(s, padLength, c, Const.STR_PAD_RIGHT);
+	}
+
+	public static function lpad( s : String, c : String, l : Int ) : String {
+		if (c.length == 0 || s.length >= l) return s;
+		var padLength = Math.ceil((l - s.length) / c.length) * c.length + s.length;
+		return Global.str_pad(s, padLength, c, Const.STR_PAD_LEFT);
+	}
+
+	public static function replace( s : String, sub : String, by : String ) : String {
+		if (sub == '') {
+			return Global.implode(by, Global.str_split(s));
+		}
+		return Global.str_replace(sub, by, s);
+	}
+
+	public static function hex( n : Int, ?digits : Int ) : String {
+		var s = Global.dechex(n);
+		var len = 8;
+		if (s.length > (null == digits ? len : (len = digits > len ? digits : len)))
+			s = s.substr(-len);
+		else if ( digits != null )
+			s = lpad(s, '0', digits);
+		return s.toUpperCase();
+	}
+
+	public static inline function fastCodeAt( s : String, index : Int ) : Int {
+		return (s.length == index ? 0 : Global.ord((s:NativeString)[index]));
+	}
+
+	public static inline function isEof( c : Int ) : Bool {
+		return c == 0;
+	}
+
+	/**
+		Returns a String that can be used as a single command line argument
+		on Unix.
+		The input will be quoted, or escaped if necessary.
+	*/
+	public static function quoteUnixArg(argument:String):String {
+		// Based on cpython's shlex.quote().
+		// https://hg.python.org/cpython/file/a3f076d4f54f/Lib/shlex.py#l278
+
+		if (argument == "")
+			return "''";
+
+		if (!~/[^a-zA-Z0-9_@%+=:,.\/-]/.match(argument))
+			return argument;
+
+		// use single quotes, and put single quotes into double quotes
+		// the string $'b is then quoted as '$'"'"'b'
+		return "'" + replace(argument, "'", "'\"'\"'") + "'";
+	}
+
+	/**
+		Character codes of the characters that will be escaped by `quoteWinArg(_, true)`.
+	*/
+	public static var winMetaCharacters = [";".code, ",".code, " ".code, "(".code, ")".code, "%".code, "!".code, "^".code, "\"".code, "<".code, ">".code, "&".code, "|".code, "\n".code, "\r".code];
+
+	/**
+		Returns a String that can be used as a single command line argument
+		on Windows.
+		The input will be quoted, or escaped if necessary, such that the output
+		will be parsed as a single argument using the rule specified in
+		http://msdn.microsoft.com/en-us/library/ms880421
+
+		Examples:
+		```
+		quoteWinArg("abc") == "abc";
+		quoteWinArg("ab c") == '"ab c"';
+		```
+	*/
+	public static function quoteWinArg(argument:String, escapeMetaCharacters:Bool):String {
+		// If there is no space, tab, back-slash, or double-quotes, and it is not an empty string.
+		if (!~/^[^ \t\\"]+$/.match(argument)) {
+
+			// Based on cpython's subprocess.list2cmdline().
+			// https://hg.python.org/cpython/file/50741316dd3a/Lib/subprocess.py#l620
+
+			var result = new StringBuf();
+			var needquote = argument.indexOf(" ") != -1 || argument.indexOf("\t") != -1 || argument == "";
+
+			if (needquote)
+				result.add('"');
+
+			var bs_buf = new StringBuf();
+			for (i in 0...argument.length) {
+				switch (argument.charCodeAt(i)) {
+					case "\\".code:
+						// Don't know if we need to double yet.
+						bs_buf.add("\\");
+					case '"'.code:
+						// Double backslashes.
+						var bs = bs_buf.toString();
+						result.add(bs);
+						result.add(bs);
+						bs_buf = new StringBuf();
+						result.add('\\"');
+					case c:
+						// Normal char
+						if (bs_buf.length > 0) {
+							result.add(bs_buf.toString());
+							bs_buf = new StringBuf();
+						}
+						result.addChar(c);
+				}
+			}
+
+			// Add remaining backslashes, if any.
+			result.add(bs_buf.toString());
+
+			if (needquote) {
+				result.add(bs_buf.toString());
+				result.add('"');
+			}
+
+			argument = result.toString();
+		}
+
+		if (escapeMetaCharacters) {
+			var result = new StringBuf();
+			for (i in 0...argument.length) {
+				var c = argument.charCodeAt(i);
+				if (winMetaCharacters.indexOf(c) >= 0) {
+					result.addChar("^".code);
+				}
+				result.addChar(c);
+			}
+			return result.toString();
+		} else {
+			return argument;
+		}
+	}
+
+}

+ 145 - 0
std/php7/_std/Sys.hx

@@ -0,0 +1,145 @@
+/*
+ * Copyright (C)2005-2016 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.
+ */
+
+import php.*;
+import sys.io.FileOutput;
+import sys.io.FileInput;
+
+@:coreApi class Sys {
+
+	public static inline function print( v : Dynamic ) : Void {
+		Global.echo(Std.string(v));
+	}
+
+	public static function println( v : Dynamic ) : Void {
+		print(v);
+		print("\n");
+	}
+
+	public static function args() : Array<String> {
+		if (Global.array_key_exists('argv', SuperGlobal._SERVER)) {
+			return @:privateAccess Array.wrap(Global.array_slice(SuperGlobal._SERVER['argv'], 1));
+		} else {
+			return [];
+		}
+	}
+
+	public static function getEnv( s : String ) : String {
+		var value = Global.getenv(s);
+		return value == false ? null : value;
+	}
+
+	public static inline function putEnv( s : String, v : String ) : Void {
+		Global.putenv('$s=$v');
+	}
+
+	public static inline function sleep( seconds : Float ) : Void {
+		return Global.usleep(Std.int(seconds * 1000000));
+	}
+
+	public static inline function setTimeLocale( loc : String ) : Bool {
+		return Global.setlocale(Const.LC_TIME, loc) != false;
+	}
+
+	public static function getCwd() : String {
+		var cwd = Global.getcwd();
+		if (cwd == false) return null;
+		var l = (cwd:String).substr(-1);
+		return (cwd:String) + (l == '/' || l == '\\' ? '' : '/');
+	}
+
+	public static inline function setCwd( s : String ) : Void {
+		Global.chdir(s);
+	}
+
+	public static function systemName() : String {
+		var s = Global.php_uname('s');
+		var p = s.indexOf(" ");
+		return (p >= 0 ? s.substr(0, p) : s);
+	}
+
+	public static function command( cmd : String, ?args : Array<String> ) : Int {
+		if (args != null) {
+			switch (systemName()) {
+				case "Windows":
+					cmd = [
+						for (a in [StringTools.replace(cmd, "/", "\\")].concat(args))
+						StringTools.quoteWinArg(a, true)
+					].join(" ");
+				case _:
+					cmd = [cmd].concat(args).map(StringTools.quoteUnixArg).join(" ");
+			}
+		}
+		var result = Boot.deref(0);
+		Global.system(cmd, result);
+		return result;
+	}
+
+	public static inline function exit( code : Int ) : Void {
+		Global.exit(code);
+	}
+
+	public static inline function time() : Float {
+		return Global.microtime(true);
+	}
+
+	public static function cpuTime() : Float {
+		return time() - SuperGlobal._SERVER['REQUEST_TIME'];
+	}
+
+	@:deprecated("Use programPath instead") public static inline function executablePath() : String {
+		return SuperGlobal._SERVER['SCRIPT_FILENAME'];
+	}
+
+	// It has to be initialized before any call to Sys.setCwd()...
+	static var _programPath = sys.FileSystem.fullPath(SuperGlobal._SERVER['SCRIPT_FILENAME']);
+	public static function programPath() : String {
+		return _programPath;
+	}
+
+	public static function environment() : Map<String,String> {
+		return php.Lib.hashOfAssociativeArray(SuperGlobal._SERVER);
+	}
+
+	public static function stdin() : haxe.io.Input {
+		return @:privateAccess new FileInput(Const.STDIN);
+	}
+
+	public static function stdout() : haxe.io.Output {
+		return @:privateAccess new FileOutput(Const.STDOUT);
+	}
+
+	public static function stderr() : haxe.io.Output {
+		return @:privateAccess new FileOutput(Const.STDERR);
+	}
+
+	public static function getChar( echo : Bool ) : Int {
+		var c = Global.fgetc(Const.STDIN);
+		if (c == false) {
+			return 0;
+		} else {
+			if(echo) Global.echo(c);
+			return Global.ord(c);
+		}
+	}
+
+}

+ 361 - 0
std/php7/_std/Type.hx

@@ -0,0 +1,361 @@
+/*
+ * Copyright (C)2005-2016 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.
+ */
+
+import php.*;
+import php.reflection.*;
+import haxe.extern.EitherType;
+
+using php.Global;
+
+enum ValueType {
+	TNull;
+	TInt;
+	TFloat;
+	TBool;
+	TObject;
+	TFunction;
+	TClass( c : Class<Dynamic> );
+	TEnum( e : Enum<Dynamic> );
+	TUnknown;
+}
+
+@:coreApi class Type {
+
+	public static function getClass<T>( o : T ) : Class<T> {
+		if(Global.is_object(o) && !Boot.isClass(o) && !Boot.isEnumValue(o)) {
+			var cls = Boot.getClass(Global.get_class(cast o));
+			return (cls == Boot.getHxAnon() ? null : cast cls);
+		} else if(Global.is_string(o)) {
+			return cast String;
+		} else {
+			return null;
+		}
+	}
+
+	public static function getEnum( o : EnumValue ) : Enum<Dynamic> {
+		if(o == null) return null;
+		return cast Boot.getClass(Global.get_class(cast o));
+	}
+
+	public static function getSuperClass( c : Class<Dynamic> ) : Class<Dynamic> {
+		if(c == null) return null;
+		var parentClass = Global.get_parent_class((cast c).phpClassName);
+		if(!parentClass) return null;
+		return cast Boot.getClass(parentClass);
+	}
+
+	public static function getClassName( c : Class<Dynamic> ) : String {
+		if(c == null) return null;
+		return Boot.getHaxeName(cast c);
+	}
+
+	public static function getEnumName( e : Enum<Dynamic> ) : String {
+		return getClassName(cast e);
+	}
+
+	public static function resolveClass( name : String ) : Class<Dynamic> {
+		if (name == null) return null;
+		switch(name) {
+			case 'Dynamic': return cast Dynamic;
+			case 'Int': return cast Int;
+			case 'Float': return cast Float;
+			case 'Bool':  return cast Bool;
+			case 'String': return String;
+			case 'Class': return cast Class;
+			case 'Enum': return cast Enum;
+		}
+
+		var phpClass = Boot.getPhpName(name);
+		if (!Global.class_exists(phpClass) && !Global.interface_exists(phpClass)) return null;
+
+		var hxClass = Boot.getClass(phpClass);
+
+		return cast hxClass;
+	}
+
+	public static function resolveEnum( name : String ) : Enum<Dynamic> {
+		if (name == null) return null;
+		if (name == 'Bool') return cast Bool;
+
+		var phpClass = Boot.getPhpName(name);
+		if (!Global.class_exists(phpClass)) return null;
+
+		var hxClass = Boot.getClass(phpClass);
+
+		return cast hxClass;
+	}
+
+	public static function createInstance<T>( cl : Class<T>, args : Array<Dynamic> ) : T {
+		if (String == cast cl) return args[0];
+
+		var phpName = getPhpName(cl);
+		if (phpName == null) return null;
+		var nativeArgs:NativeArray = @:privateAccess args.arr;
+		return Syntax.construct(phpName, Syntax.splat(nativeArgs));
+	}
+
+	public static function createEmptyInstance<T>( cl : Class<T> ) : T {
+		if (String == cast cl) return cast '';
+		if (Array == cast cl) return cast [];
+
+		var phpName = getPhpName(cl);
+		if (phpName == null) return null;
+
+		var reflection = new ReflectionClass(phpName);
+		return reflection.newInstanceWithoutConstructor();
+	}
+
+	public static function createEnum<T>( e : Enum<T>, constr : String, ?params : Array<Dynamic> ) : T {
+		if (e == null || constr == null) return null;
+
+		var phpName = getPhpName(e);
+		if (phpName == null) return null;
+
+		if (!Global.in_array(constr, Syntax.staticCall(phpName, "__hx__list"))) {
+			throw 'No such constructor $constr';
+		}
+
+		var paramsCounts:NativeAssocArray<Int> = Syntax.staticCall(phpName, "__hx__paramsCount");
+		if ((params == null && paramsCounts[constr] != 0) || (params != null && params.length != paramsCounts[constr])) {
+			throw 'Provided parameters count does not match expected parameters count';
+		}
+
+		if (params == null) {
+			return Syntax.staticCall(phpName, constr);
+		} else {
+			var nativeArgs:NativeArray = @:privateAccess params.arr;
+			return Syntax.staticCall(phpName, constr, Syntax.splat(nativeArgs));
+		}
+	}
+
+	public static function createEnumIndex<T>( e : Enum<T>, index : Int, ?params : Array<Dynamic> ) : T {
+		if (e == null || index == null) return null;
+
+		var phpName = getPhpName(e);
+		if (phpName == null) return null;
+
+		var constructors:NativeIndexedArray<String> = Syntax.staticCall(phpName, "__hx__list");
+		if (index < 0 || index >= Global.count(constructors)) {
+			throw '$index is not a valid enum constructor index';
+		}
+
+		var constr = constructors[index];
+		var paramsCounts:NativeAssocArray<Int> = Syntax.staticCall(phpName, "__hx__paramsCount");
+		if ((params == null && paramsCounts[constr] != 0) || (params != null && params.length != paramsCounts[constr])) {
+			throw 'Provided parameters count does not match expected parameters count';
+		}
+
+		if (params == null) {
+			return Syntax.staticCall(phpName, constr);
+		} else {
+			var nativeArgs:NativeArray = @:privateAccess params.arr;
+			return Syntax.staticCall(phpName, constr, Syntax.splat(nativeArgs));
+		}
+	}
+
+	public static function getInstanceFields( c : Class<Dynamic> ) : Array<String> {
+		if (c == null) return null;
+		if (c == String) {
+			return [
+				'substr', 'charAt', 'charCodeAt', 'indexOf',
+				'lastIndexOf', 'split', 'toLowerCase',
+				'toUpperCase', 'toString', 'length'
+			];
+		}
+
+		var phpName = getPhpName(c);
+		if (phpName == null) return null;
+
+		var reflection = new ReflectionClass(phpName);
+
+		var methods = new NativeArray();
+		for (m in reflection.getMethods()) {
+			var method:ReflectionMethod = m;
+			if (!method.isStatic()) {
+				var name = method.getName();
+				if (!isServiceFieldName(name)) {
+					methods.array_push(name);
+				}
+			}
+		}
+
+		var properties = new NativeArray();
+		for (p in reflection.getProperties()) {
+			var property:ReflectionProperty = p;
+			if (!property.isStatic()) {
+				var name = property.getName();
+				if (!isServiceFieldName(name)) {
+					properties.array_push(name);
+				}
+			}
+		}
+		properties = Global.array_diff(properties, methods);
+
+		var fields = Global.array_merge(properties, methods);
+
+		return @:privateAccess Array.wrap(fields);
+	}
+
+	public static function getClassFields( c : Class<Dynamic> ) : Array<String> {
+		if (c == null) return null;
+		if (c == String) return ['fromCharCode'];
+
+		var phpName = getPhpName(c);
+		if (phpName == null) return null;
+
+		var reflection = new ReflectionClass(phpName);
+
+		var methods = new NativeArray();
+		for (m in reflection.getMethods(ReflectionMethod.IS_STATIC)) {
+			//TODO: report an issue on invalid type inference for iteration over `NativeIndexedArray`
+			var m:ReflectionMethod = m;
+			var name = m.getName();
+			if (!isServiceFieldName(name) && phpName == m.getDeclaringClass().getName()) {
+				methods.array_push(name);
+			}
+		}
+
+		var properties = new NativeArray();
+		for (p in reflection.getProperties(ReflectionProperty.IS_STATIC)) {
+			var p:ReflectionMethod = p;
+			var name = p.getName();
+			if (!isServiceFieldName(name) && phpName == p.getDeclaringClass().getName()) {
+				properties.array_push(name);
+			}
+		}
+		properties = Global.array_diff(properties, methods);
+		var fields = Global.array_merge(properties, methods);
+
+		return @:privateAccess Array.wrap(fields);
+	}
+
+	public static function getEnumConstructs( e : Enum<Dynamic> ) : Array<String> {
+		if (e == null) return null;
+		return @:privateAccess Array.wrap(untyped e.__hx__list());
+	}
+
+	public static function typeof( v : Dynamic ) : ValueType {
+		if (v == null) return TNull;
+
+		if (v.is_object()) {
+			if (Reflect.isFunction(v)) return TFunction;
+			if (Syntax.instanceof(v, StdClass)) return TObject;
+			if (Boot.isClass(v)) return TObject;
+
+			var hxClass = Boot.getClass(Global.get_class(v));
+			if (Boot.isEnumValue(v)) return TEnum(cast hxClass);
+			return TClass(cast hxClass);
+		}
+
+		if (v.is_bool()) return TBool;
+		if (v.is_int()) return TInt;
+		if (v.is_float()) return TFloat;
+		if (v.is_string()) return TClass(String);
+
+		return TUnknown;
+	}
+
+	public static function enumEq<T:EnumValue>( a : T, b : T ) : Bool {
+		if (a == b) return true;
+		if (a == null || b == null) return false;
+
+		try {
+			if (Global.get_class(cast a) != Global.get_class(cast b)) return false;
+			if (enumIndex(a) != enumIndex(b)) return false;
+
+			var aParams:NativeIndexedArray<Dynamic> = untyped a.params;
+			var bParams:NativeIndexedArray<Dynamic> = untyped b.params;
+			for (i in 0...Global.count(aParams)) {
+				//enums
+				if (Boot.isEnumValue(aParams[i])) {
+					if (!enumEq(aParams[i], bParams[i])) {
+						return false;
+					}
+					continue;
+				}
+				//functions
+				if (Reflect.isFunction(aParams[i])) {
+					if (!Reflect.compareMethods(aParams[i], bParams[i])) {
+						return false;
+					}
+					continue;
+				}
+				//everything else
+				if (aParams[i] != bParams[i]) {
+					return false;
+				}
+			}
+
+			return true;
+		} catch (e:Dynamic) {
+			return false;
+		}
+	}
+
+	public static function enumConstructor( e : EnumValue ) : String {
+		return untyped e.tag;
+	}
+
+	public inline static function enumParameters( e : EnumValue ) : Array<Dynamic> {
+		return @:privateAccess Array.wrap(untyped e.params);
+	}
+
+	public inline static function enumIndex( e : EnumValue ) : Int {
+		return untyped e.index;
+	}
+
+	public static function allEnums<T>( e : Enum<T> ) : Array<T> {
+		if (e == null) return null;
+
+		var phpName = getPhpName(e);
+		if (phpName == null) return null;
+
+		var result = [];
+
+		for (name in getEnumConstructs(e)) {
+			var reflection = new ReflectionMethod(phpName, name);
+			if (reflection.getNumberOfParameters() == 0) {
+				result.push(reflection.invoke(null));
+			}
+		}
+
+		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.
+	 **/
+	static inline function isServiceFieldName(name:String) : Bool {
+		return (name == '__construct' || name.indexOf('__hx__') == 0);
+	}
+}
+

+ 142 - 0
std/php7/_std/haxe/CallStack.hx

@@ -0,0 +1,142 @@
+package haxe;
+
+import php.*;
+
+private typedef NativeTrace = NativeIndexedArray<NativeAssocArray<Dynamic>>;
+
+/**
+	Elements return by `CallStack` methods.
+**/
+enum StackItem {
+	CFunction;
+	Module( m : String );
+	FilePos( s : Null<StackItem>, file : String, line : Int );
+	Method( classname : String, method : String );
+	LocalFunction( ?v : Int );
+}
+
+@:dox(hide)
+@:noCompletion
+class CallStack {
+	static var lastExceptionTrace : NativeTrace;
+
+	/**
+		Return the call stack elements, or an empty array if not available.
+	**/
+	public static function callStack() : Array<StackItem> {
+		return makeStack(Global.debug_backtrace(Const.DEBUG_BACKTRACE_IGNORE_ARGS));
+	}
+
+	/**
+		Return the exception stack : this is the stack elements between
+		the place the last exception was thrown and the place it was
+		caught, or an empty array if not available.
+	**/
+	public static function exceptionStack() : Array<StackItem> {
+		return makeStack(lastExceptionTrace == null ? new NativeIndexedArray() : lastExceptionTrace);
+	}
+
+	/**
+		Returns a representation of the stack as a printable string.
+	**/
+	public static function toString( stack : Array<StackItem> ) {
+		var b = new StringBuf();
+		for( s in stack ) {
+			b.add("\nCalled from ");
+			itemToString(b,s);
+		}
+		return b.toString();
+	}
+
+	static function itemToString( b:StringBuf, s ) {
+		switch( s ) {
+			case CFunction:
+				b.add("a C function");
+			case Module(m):
+				b.add("module ");
+				b.add(m);
+			case FilePos(s,file,line):
+				if( s != null ) {
+					itemToString(b,s);
+					b.add(" (");
+				}
+				b.add(file);
+				b.add(" line ");
+				b.add(line);
+				if( s != null ) b.add(")");
+			case Method(cname,meth):
+				b.add(cname);
+				b.add(".");
+				b.add(meth);
+			case LocalFunction(n):
+				b.add("local function");
+		}
+	}
+
+	@:keep
+	static function saveExceptionTrace( e:Throwable ) : Void {
+		lastExceptionTrace = e.getTrace();
+
+		//Reduce exception stack to the place where exception was caught
+		var currentTrace = Global.debug_backtrace(Const.DEBUG_BACKTRACE_IGNORE_ARGS);
+		var count = Global.count(currentTrace);
+
+		for (i in -(count - 1)...1) {
+			var exceptionEntry:NativeAssocArray<Dynamic> = Global.end(lastExceptionTrace);
+
+			if(!Global.isset(exceptionEntry['file'])) {
+				Global.array_pop(lastExceptionTrace);
+			} else if (currentTrace[-i]['file'] == exceptionEntry['file'] && currentTrace[-i]['line'] == exceptionEntry['line']) {
+				Global.array_pop(lastExceptionTrace);
+			} else {
+				break;
+			}
+		}
+
+		//Remove arguments from trace to avoid blocking some objects from GC
+		var count = Global.count(lastExceptionTrace);
+		for (i in 0...count) {
+			lastExceptionTrace[i]['args'] = new NativeArray();
+		}
+
+		var thrownAt = new NativeAssocArray<Dynamic>();
+		thrownAt['function'] = '';
+		thrownAt['line'] = e.getLine();
+		thrownAt['file'] = e.getFile();
+		thrownAt['class'] = '';
+		thrownAt['args'] = new NativeArray();
+		Global.array_unshift(lastExceptionTrace, thrownAt);
+	}
+
+	static function makeStack (native:NativeTrace) : Array<StackItem> {
+		var result = [];
+		var count = Global.count(native);
+
+		for (i in 0...count) {
+			var entry = native[i];
+			var item = null;
+
+			if (i + 1 < count) {
+				var next = native[i + 1];
+
+				if(!Global.isset(next['function'])) next['function'] = '';
+				if(!Global.isset(next['class'])) next['class'] = '';
+
+				if ((next['function']:String).indexOf('{closure}') >= 0) {
+					item = LocalFunction();
+				} else if ((next['class']:String).length > 0 && (next['function']:String).length > 0) {
+					var cls = Boot.getClassName(next['class']);
+					item = Method(cls, next['function']);
+				}
+			}
+			if (Global.isset(entry['file'])) {
+				result.push(FilePos(item, entry['file'], entry['line']));
+			} else if (item != null) {
+				result.push(item);
+			}
+		}
+
+		return result;
+	}
+
+}

+ 111 - 0
std/php7/_std/haxe/Json.hx

@@ -0,0 +1,111 @@
+/*
+ * Copyright (C)2005-2016 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 haxe;
+
+import php.*;
+import haxe.format.JsonPrinter;
+
+@:coreApi
+class Json {
+
+	public static inline function parse( text : String ) : Dynamic {
+		#if haxeJSON
+			return haxe.format.JsonParser.parse(text);
+		#else
+			return phpJsonDecode(text);
+		#end
+	}
+
+	public static inline function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space:String ) : String {
+		#if haxeJSON
+			return JsonPrinter.print(value, replacer, space);
+		#else
+			return phpJsonEncode(value, replacer, space);
+		#end
+	}
+
+	static function phpJsonDecode(json:String):Dynamic {
+		var value = Global.json_decode(json);
+		return convertAfterDecode(value);
+	}
+
+	static function convertAfterDecode(value:Dynamic):Dynamic {
+		if (Global.is_object(value)) {
+			var result = new NativeAssocArray();
+			var data = Syntax.array(value);
+			Syntax.foreach(data, function(fieldName:String, fieldValue:Dynamic) {
+				result[fieldName] = convertAfterDecode(fieldValue);
+			});
+
+			return Boot.createAnon(result);
+		}
+
+		if (Global.is_array(value)) {
+			var result = new NativeIndexedArray();
+			Syntax.foreach(value, function(index:Int, item:Dynamic) {
+				result[index] = convertAfterDecode(item);
+			});
+
+			return @:privateAccess Array.wrap(result);
+		}
+
+		return value;
+	}
+
+	static function phpJsonEncode(value:Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space:String):String {
+		if(null != replacer || null != space) {
+			return JsonPrinter.print(value, replacer, space);
+		}
+
+		var json = Global.json_encode(convertBeforeEncode(value));
+		if (Global.json_last_error() != Const.JSON_ERROR_NONE) {
+			return throw Global.json_last_error_msg();
+		}
+		return json;
+	}
+
+	static function convertBeforeEncode(value:Dynamic):Dynamic {
+		if (Syntax.instanceof(value, Array)) {
+			var result = new NativeIndexedArray();
+			Syntax.foreach(value.arr, function(index:Int, item:Dynamic) {
+				result[index] = convertBeforeEncode(item);
+			});
+
+			return result;
+		}
+
+		if (Global.is_object(value)) {
+			var result = new NativeAssocArray();
+			Syntax.foreach(value, function(fieldName:String, fieldValue:Dynamic) {
+				result[fieldName] = convertBeforeEncode(fieldValue);
+			});
+
+			return result;
+		}
+
+		if (Global.is_float(value) && !Global.is_finite(value)) {
+			return null;
+		}
+
+		return value;
+	}
+}

+ 68 - 0
std/php7/_std/haxe/Resource.hx

@@ -0,0 +1,68 @@
+/*
+ * Copyright (C)2005-2016 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 haxe;
+
+import php.*;
+import haxe.io.Bytes;
+import haxe.crypto.Base64;
+
+@:coreApi
+class Resource {
+
+	static function cleanName(name : String) : String {
+		return ~/[\\\/:?"*<>|]/.replace(name, '_');
+	}
+
+	static function getDir() : String {
+		return Global.dirname(Const.__FILE__) + "/../../res";
+	}
+
+	@:access(haxe.io.Path.escape)
+	static function getPath(name : String) : String {
+		return getDir()+'/'+haxe.io.Path.escape(name);
+	}
+
+	@:access(haxe.io.Path.unescape)
+	public static function listNames() : Array<String> {
+		var a = sys.FileSystem.readDirectory(getDir());
+		if(a[0] == '.') a.shift();
+		if(a[0] == '..') a.shift();
+		return a.map(function(s) return haxe.io.Path.unescape(s));
+	}
+
+	public static function getString( name : String ) : String {
+		var path = getPath(name);
+		return if (!sys.FileSystem.exists(path))
+			null;
+		else
+			sys.io.File.getContent(path);
+	}
+
+	public static function getBytes( name : String ) : haxe.io.Bytes {
+		var path = getPath(name);
+		return if (!sys.FileSystem.exists(path))
+			null;
+		else
+			sys.io.File.getBytes(path);
+	}
+
+}

+ 88 - 0
std/php7/_std/haxe/Utf8.hx

@@ -0,0 +1,88 @@
+/*
+ * Copyright (C)2005-2016 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 haxe;
+
+import php.Global;
+
+@:coreApi
+class Utf8 {
+
+	var __b : String;
+
+	public function new( ?size : Int ) : Void {
+		__b = '';
+	}
+
+	public function addChar( c : Int ) : Void {
+		__b += uchr(c);
+	}
+
+	public function toString() : String {
+		return __b;
+	}
+
+	public static function encode( s : String ) : String {
+		return Global.utf8_encode(s);
+	}
+
+	public static function decode( s : String ) : String {
+		return Global.utf8_decode(s);
+	}
+
+	public static function iter(s : String, chars : Int -> Void ) : Void {
+		var len = length(s);
+		for(i in 0...len) {
+			chars(charCodeAt(s, i));
+		}
+	}
+
+	public static function charCodeAt( s : String, index : Int ) : Int {
+		return uord(sub(s, index, 1));
+	}
+
+	static function uchr(i : Int) : String {
+		return Global.mb_convert_encoding(Global.pack('N', i), 'UTF-8', 'UCS-4BE');
+	}
+
+	static function uord(s : String) : Int {
+		var c = Global.unpack('N', Global.mb_convert_encoding(s, 'UCS-4BE', 'UTF-8'));
+		return c[1];
+	}
+
+	public static function validate( s : String ) : Bool {
+		return Global.mb_check_encoding(s, enc);
+	}
+
+	public static function length( s : String ) : Int {
+		return Global.mb_strlen(s, enc);
+	}
+
+	public static function compare( a : String, b : String ) : Int {
+		return Global.strcmp(a, b);
+	}
+
+	public static function sub( s : String, pos : Int, len : Int ) : String {
+		return Global.mb_substr(s, pos, len, enc);
+	}
+
+	private static inline var enc = "UTF-8";
+}

+ 39 - 0
std/php7/_std/haxe/crypto/Md5.hx

@@ -0,0 +1,39 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.crypto;
+
+import php.Global;
+import haxe.io.Bytes;
+
+/**
+	Creates a MD5 of a String.
+**/
+class Md5 {
+
+	public static inline function encode( s : String ) : String {
+		return Global.md5(s);
+	}
+
+	public static inline function make( b : haxe.io.Bytes ) : haxe.io.Bytes {
+        return Bytes.ofData(Global.md5(b.getData(), true));
+	}
+}

+ 39 - 0
std/php7/_std/haxe/crypto/Sha1.hx

@@ -0,0 +1,39 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.crypto;
+
+import php.Global;
+import haxe.io.Bytes;
+
+/**
+	Creates a Sha1 of a String.
+*/
+class Sha1 {
+
+	public static inline function encode( s:String ) : String {
+		return Global.sha1(s);
+	}
+
+	public static inline function make( b : haxe.io.Bytes ) : haxe.io.Bytes {
+		return Bytes.ofData(Global.sha1(b.getData(), true));
+	}
+}

+ 39 - 0
std/php7/_std/haxe/crypto/Sha224.hx

@@ -0,0 +1,39 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.crypto;
+
+import php.Global;
+import haxe.io.Bytes;
+
+/**
+	Creates a Sha224 of a String.
+*/
+class Sha224 {
+
+	public static inline function encode( s:String ) : String {
+		return Global.hash('sha224', s);
+	}
+
+	public static function make( b : haxe.io.Bytes ) : haxe.io.Bytes {
+		return Bytes.ofData(Global.hash('sha224', b.getData(), true));
+	}
+}

+ 39 - 0
std/php7/_std/haxe/crypto/Sha256.hx

@@ -0,0 +1,39 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.crypto;
+
+import php.Global;
+import haxe.io.Bytes;
+
+/**
+	Creates a Sha256 of a String.
+*/
+class Sha256 {
+
+	public static inline function encode( s:String ) : String {
+		return Global.hash('sha256', s);
+	}
+
+	public static function make( b : haxe.io.Bytes ) : haxe.io.Bytes {
+		return Bytes.ofData(Global.hash('sha256', b.getData(), true));
+	}
+}

+ 98 - 0
std/php7/_std/haxe/ds/IntMap.hx

@@ -0,0 +1,98 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.ds;
+
+import php.Syntax;
+import php.Global;
+import php.NativeArray;
+import php.NativeIndexedArray;
+
+@:coreApi class IntMap<T> implements haxe.Constraints.IMap<Int,T> {
+
+	var data:NativeIndexedArray<T>;
+
+	/**
+		Creates a new IntMap.
+	**/
+	public function new() : Void {
+		data = new NativeIndexedArray();
+	}
+
+	/**
+		See `Map.set`
+	**/
+	public inline function set( key : Int, value : T ) : Void {
+		data[key] = value;
+	}
+
+	/**
+		See `Map.get`
+	**/
+	public inline function get( key : Int ) : Null<T> {
+		return Global.isset(data[key]) ? data[key] : null;
+	}
+
+	/**
+		See `Map.exists`
+	**/
+	public inline function exists( key : Int ) : Bool {
+		return Global.array_key_exists(key, data);
+	}
+
+	/**
+		See `Map.remove`
+	**/
+	public function remove( key : Int ) : Bool {
+		if (Global.array_key_exists(key, data)) {
+			Global.unset(data[key]);
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+		See `Map.keys`
+	**/
+	public inline function keys() : Iterator<Int> {
+		return Global.array_keys(data).iterator();
+	}
+
+	/**
+		See `Map.iterator`
+	**/
+	public inline function iterator() : Iterator<T> {
+		return Global.array_values(data).iterator();
+	}
+
+	/**
+		See `Map.toString`
+	**/
+	public function toString() : String {
+		var parts = new NativeArray();
+		Syntax.foreach(data, function(key:Int, value:T) {
+			Global.array_push(parts, '$key => ' + Std.string(value));
+		});
+
+		return '{' + Global.implode(', ', parts) + '}';
+	}
+}

+ 82 - 0
std/php7/_std/haxe/ds/ObjectMap.hx

@@ -0,0 +1,82 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.ds;
+
+import php.*;
+
+@:coreApi
+class ObjectMap <K:{ }, V> implements haxe.Constraints.IMap<K,V> {
+	var _keys:NativeAssocArray<K>;
+	var _values:NativeAssocArray<V>;
+
+	public function new():Void {
+		_keys = new NativeAssocArray();
+		_values = new NativeAssocArray();
+	}
+
+	public function set(key:K, value:V):Void untyped {
+		var id = Global.spl_object_hash(key);
+		_keys[id] = key;
+		_values[id] = value;
+	}
+
+	public function get(key:K):Null<V> {
+		var id = Global.spl_object_hash(key);
+		return Global.isset(_values[id]) ? _values[id] : null;
+	}
+
+	public function exists(key:K):Bool {
+		return Global.array_key_exists(Global.spl_object_hash(key), _values);
+	}
+
+	public function remove( key : K ) : Bool {
+		var id = Global.spl_object_hash(key);
+		if (Global.array_key_exists(id, _values)) {
+			Global.unset(_keys[id], _values[id]);
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	public inline function keys() : Iterator<K> {
+		return _keys.iterator();
+	}
+
+	public inline function iterator() : Iterator<V> {
+		return _values.iterator();
+	}
+
+	public function toString() : String {
+		var s = "{";
+		var it = keys();
+		for( i in it ) {
+			s += Std.string(i);
+			s += " => ";
+			s += Std.string(get(i));
+			if( it.hasNext() )
+				s += ", ";
+		}
+		return s + "}";
+	}
+}

+ 74 - 0
std/php7/_std/haxe/ds/StringMap.hx

@@ -0,0 +1,74 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.ds;
+
+import php.Syntax;
+import php.Global;
+import php.NativeArray;
+import php.NativeAssocArray;
+import haxe.Constraints;
+
+@:coreApi class StringMap<T> implements IMap<String,T> {
+	private var data : NativeAssocArray<T>;
+
+	public inline function new() : Void {
+		data = new NativeAssocArray();
+	}
+
+	public inline function set( key : String, value : T ) : Void {
+		data[key] = value;
+	}
+
+	public inline function get( key : String ) : Null<T> {
+		return Global.isset(data[key]) ? data[key] : null;
+	}
+
+	public inline function exists( key : String ) : Bool {
+		return Global.array_key_exists(key, data);
+	}
+
+	public function remove( key : String ) : Bool {
+		if (Global.array_key_exists(key, data)) {
+			Global.unset(data[key]);
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	public inline function keys() : Iterator<String> {
+		return Global.array_map('strval', Global.array_keys(data)).iterator();
+	}
+
+	public inline function iterator() : Iterator<T> {
+		return data.iterator();
+	}
+
+	public function toString() : String {
+		var parts = new NativeArray();
+		Syntax.foreach(data, function(key:String, value:T) {
+			Global.array_push(parts, '$key => ' + Std.string(value));
+		});
+
+		return '{' + Global.implode(', ', parts) + '}';
+	}
+}

+ 206 - 0
std/php7/_std/haxe/io/Bytes.hx

@@ -0,0 +1,206 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.io;
+
+class Bytes {
+
+	public var length(default,null) : Int;
+
+	var b:BytesData;
+
+	function new(length:Int, b:BytesData) : Void {
+		this.length = length;
+		this.b = b;
+	}
+
+	public inline function get( pos : Int ) : Int {
+		return b.get(pos);
+	}
+
+	public inline function set( pos : Int, v : Int ) : Void {
+		b.set(pos, v);
+	}
+
+	public inline function blit( pos : Int, src : Bytes, srcpos : Int, len : Int ) : Void {
+		if( pos < 0 || srcpos < 0 || len < 0 || pos + len > length || srcpos + len > src.length ) {
+			throw Error.OutsideBounds;
+		} else {
+			b.blit(pos, src.b, srcpos, len);
+		}
+	}
+
+	public function fill( pos : Int, len : Int, value : Int ) : Void {
+		for(i in pos...pos+len) b.set(i, value);
+	}
+
+	public inline function sub( pos : Int, len : Int ) : Bytes {
+		if( pos < 0 || len < 0 || pos + len > length ) {
+			throw Error.OutsideBounds;
+		} else {
+			return new Bytes(len, b.sub(pos, len));
+		}
+	}
+
+	public inline function compare( other : Bytes ) : Int {
+		return b.compare(other.b);
+	}
+
+	/**
+		Returns the IEEE double precision value at given position (in low endian encoding).
+		Result is unspecified if reading outside of the bounds
+	**/
+	public function getDouble( pos : Int ) : Float {
+		return FPHelper.i64ToDouble(getInt32(pos),getInt32(pos+4));
+	}
+
+	/**
+		Returns the IEEE single precision value at given position (in low endian encoding).
+		Result is unspecified if reading outside of the bounds
+	**/
+	public function getFloat( pos : Int ) : Float {
+		var b = new haxe.io.BytesInput(this,pos,4);
+		return b.readFloat();
+	}
+
+	/**
+		Store the IEEE double precision value at given position in low endian encoding.
+		Result is unspecified if writing outside of the bounds.
+	**/
+	public function setDouble( pos : Int, v : Float ) : Void {
+		var i = FPHelper.doubleToI64(v);
+		setInt32(pos, i.low);
+		setInt32(pos + 4, i.high);
+	}
+
+	/**
+		Store the IEEE single precision value at given position in low endian encoding.
+		Result is unspecified if writing outside of the bounds.
+	**/
+	public function setFloat( pos : Int, v : Float ) : Void {
+		setInt32(pos, FPHelper.floatToI32(v));
+	}
+
+	/**
+		Returns the 16 bit unsigned integer at given position (in low endian encoding).
+	**/
+	public inline function getUInt16( pos : Int ) : Int {
+		return get(pos) | (get(pos + 1) << 8);
+	}
+
+	/**
+		Store the 16 bit unsigned integer at given position (in low endian encoding).
+	**/
+	public inline function setUInt16( pos : Int, v : Int ) : Void {
+		set(pos, v);
+		set(pos + 1, v >> 8);
+	}
+
+	/**
+		Returns the 32 bit integer at given position (in low endian encoding).
+	**/
+	public inline function getInt32( pos : Int ) : Int {
+		var v = get(pos) | (get(pos + 1) << 8) | (get(pos + 2) << 16) | (get(pos+3) << 24);
+		return if( v & 0x80000000 != 0 ) v | 0x80000000 else v;
+	}
+
+	/**
+		Returns the 64 bit integer at given position (in low endian encoding).
+	**/
+	public inline function getInt64( pos : Int ) : haxe.Int64 {
+		return haxe.Int64.make(getInt32(pos+4), getInt32(pos));
+	}
+
+	/**
+		Store the 32 bit integer at given position (in low endian encoding).
+	**/
+	public inline function setInt32( pos : Int, v : Int ) : Void {
+		set(pos, v);
+		set(pos + 1, v >> 8);
+		set(pos + 2, v >> 16);
+		set(pos + 3, v >>> 24);
+	}
+
+	/**
+		Store the 64 bit integer at given position (in low endian encoding).
+	**/
+	public inline function setInt64( pos : Int, v : haxe.Int64 ) : Void {
+		setInt32(pos, v.low);
+		setInt32(pos + 4, v.high);
+	}
+
+	public inline function getString( pos : Int, len : Int ) : String {
+		if( pos < 0 || len < 0 || pos + len > length ) {
+			throw Error.OutsideBounds;
+		} else {
+			return b.getString(pos, len);
+		}
+	}
+
+	@:deprecated("readString is deprecated, use getString instead")
+	@:noCompletion
+	public inline function readString(pos:Int, len:Int):String {
+		return getString(pos, len);
+	}
+
+	public function toString() : String {
+		return b;
+	}
+
+	public function toHex() : String {
+		var s = new StringBuf();
+		var chars = [];
+		var str = "0123456789abcdef";
+		for( i in 0...str.length )
+			chars.push(str.charCodeAt(i));
+		for( i in 0...length ) {
+			var c = get(i);
+			s.addChar(chars[c >> 4]);
+			s.addChar(chars[c & 15]);
+		}
+		return s.toString();
+	}
+
+	public inline function getData() : BytesData {
+		return b;
+	}
+
+	public static function alloc( length : Int ) : Bytes {
+		return new Bytes(length, BytesData.alloc(length));
+	}
+
+	public static inline function ofString( s : String ) : Bytes {
+		return new Bytes(s.length, s);
+	}
+
+	public static inline function ofData( b : BytesData ) : Bytes {
+		return new Bytes(b.length, b);
+	}
+
+	/**
+		Read the most efficiently possible the n-th byte of the data.
+		Behavior when reading outside of the available data is unspecified.
+	**/
+	public inline static function fastGet( b : BytesData, pos : Int ) : Int {
+		return b.get(pos);
+	}
+
+}

+ 89 - 0
std/php7/_std/haxe/io/BytesBuffer.hx

@@ -0,0 +1,89 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.io;
+
+import php.*;
+
+class BytesBuffer {
+	var b : String;
+
+	/** The length of the buffer in bytes. **/
+	public var length(get,never) : Int;
+
+	public function new() {
+		b = "";
+	}
+
+	public inline function addByte( byte : Int ) {
+		Syntax.binop(b, '.=', Global.chr(byte));
+	}
+
+	public inline function add( src : Bytes ) {
+		Syntax.binop(b, '.=', src.getData().toNativeString());
+	}
+
+	public inline function addString( v : String ) {
+		Syntax.binop(b, '.=', v);
+	}
+
+	public function addInt32( v : Int ) {
+		addByte(v&0xFF);
+		addByte((v>>8)&0xFF);
+		addByte((v>>16)&0xFF);
+		addByte(v>>>24);
+	}
+
+	public function addInt64( v : haxe.Int64 ) {
+		addInt32(v.low);
+		addInt32(v.high);
+	}
+
+	public inline function addFloat( v : Float ) {
+		addInt32(FPHelper.floatToI32(v));
+	}
+
+	public inline function addDouble( v : Float ) {
+		addInt64(FPHelper.doubleToI64(v));
+	}
+
+	public inline function addBytes( src : Bytes, pos : Int, len : Int ) {
+		if( pos < 0 || len < 0 || pos + len > src.length ) {
+			throw Error.OutsideBounds;
+		} else {
+			Syntax.binop(b, '.=', src.getData().sub(pos, len).toString());
+		}
+	}
+
+	/**
+		Returns either a copy or a reference of the current bytes.
+		Once called, the buffer can no longer be used.
+	**/
+	public function getBytes() : Bytes untyped {
+		var bytes = new Bytes(b.length, b);
+		b = null;
+		return bytes;
+	}
+
+	inline function get_length() : Int {
+		return b.length;
+	}
+}

+ 88 - 0
std/php7/_std/haxe/io/BytesData.hx

@@ -0,0 +1,88 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.io;
+
+import php.*;
+
+private class Container {
+	public var s:NativeString;
+	public inline function new(s:NativeString) this.s = s;
+}
+
+abstract BytesData(Container) from Container to Container {
+
+	public var length (get,never):Int;
+
+	public static inline function alloc (length:Int):BytesData {
+		return Global.str_repeat(Global.chr(0), length);
+	}
+
+	@:arrayAccess
+	public inline function get (pos:Int):Int {
+		return Global.ord(this.s[pos]);
+	}
+
+	@:arrayAccess
+	public inline function set (index:Int, val:Int):Void {
+		this.s = Global.substr_replace(this.s, Global.chr(val), index, 1);
+	}
+
+	public inline function compare (other:BytesData):Int {
+		return Syntax.binop(this.s, '<=>', (other:Container).s);
+	}
+
+	public inline function getString (pos:Int, len:Int):String {
+		return Global.substr(this.s, pos, len);
+	}
+
+	public inline function sub (pos:Int, len:Int):BytesData {
+		return (Global.substr(this.s, pos, len):String);
+	}
+
+	public inline function blit (pos : Int, src : BytesData, srcpos : Int, len : Int):Void {
+		this.s = Syntax.binop(Syntax.binop(Global.substr(this.s, 0, pos), '.', Global.substr(src, srcpos, len)), '.', Global.substr(this.s, pos + len));
+	}
+
+	inline function get_length ():Int {
+		return Global.strlen(this.s);
+	}
+
+	@:from
+	static inline function fromNativeString (s:NativeString):BytesData {
+		return new Container(s);
+	}
+
+	@:to
+	public inline function toNativeString ():NativeString {
+		return this.s;
+	}
+
+	@:from
+	static inline function fromString (s:String):BytesData {
+		return new Container(s);
+	}
+
+	@:to
+	public inline function toString ():String {
+		return this.s;
+	}
+}

+ 79 - 0
std/php7/_std/haxe/io/BytesInput.hx

@@ -0,0 +1,79 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.io;
+
+class BytesInput extends Input {
+	var b : BytesData;
+	var pos : Int;
+	var len : Int;
+	var totlen : Int;
+
+	/** The current position in the stream in bytes. */
+	public var position(get,set) : Int;
+
+	/** The length of the stream in bytes. */
+	public var length(get,never) : Int;
+
+	public function new( b : Bytes, ?pos : Int, ?len : Int ) {
+		if( pos == null ) pos = 0;
+		if( len == null ) len = b.length - pos;
+		if( pos < 0 || len < 0 || pos + len > b.length ) throw Error.OutsideBounds;
+
+		this.b = b.getData();
+		this.pos = pos;
+		this.len = len;
+		this.totlen = len;
+	}
+
+	inline function get_position() : Int {
+		return pos;
+	}
+
+	inline function get_length() : Int {
+		return totlen;
+	}
+
+	function set_position( p : Int ) : Int {
+		if( p < 0 ) p = 0;
+		else if( p > length ) p = length;
+		len = totlen - p;
+		return pos = p;
+	}
+
+	public override function readByte() : Int {
+		return b[pos++];
+	}
+
+	public override function readBytes( buf : Bytes, pos, len ) : Int {
+		if( pos < 0 || len < 0 || pos + len > buf.length )
+			throw Error.OutsideBounds;
+		if( this.len == 0 && len > 0 )
+			throw new Eof();
+		if( this.len < len )
+			len = this.len;
+		buf.getData().blit(pos, b, this.pos, len);
+		this.pos += len;
+		this.len -= len;
+
+		return len;
+	}
+}

+ 57 - 0
std/php7/_std/haxe/io/BytesOutput.hx

@@ -0,0 +1,57 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.io;
+
+class BytesOutput extends Output {
+
+	var b : BytesBuffer;
+
+	/** The length of the stream in bytes. **/
+	public var length(get,never) : Int;
+
+	public function new() {
+		b = new BytesBuffer();
+	}
+
+	override function writeByte(c) {
+		b.addByte(c);
+	}
+
+	override function writeBytes( buf : Bytes, pos, len ) : Int {
+		b.addBytes(buf,pos,len);
+		return len;
+	}
+
+	/**
+		Returns the `Bytes` of this output.
+
+		This function should not be called more than once on a given
+		`BytesOutput` instance.
+	**/
+	public function getBytes() : Bytes {
+		return b.getBytes();
+	}
+
+	inline function get_length() : Int {
+		return b.length;
+	}
+}

+ 61 - 0
std/php7/_std/haxe/io/FPHelper.hx

@@ -0,0 +1,61 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.io;
+
+import php.*;
+
+/**
+	Helper that converts between floating point and binary representation.
+	Always works in low-endian encoding.
+**/
+class FPHelper {
+
+	static var isLittleEndian : Bool = Global.unpack('S','\x01\x00')[1] == 1;
+	static var i64tmp = Int64.ofInt(0);
+
+	public static inline function i32ToFloat( i : Int ) : Float {
+		return Global.unpack('f', Global.pack('l', i))[1];
+	}
+
+	public static inline function floatToI32( f : Float ) : Int {
+		return Global.unpack('l', Global.pack('f', f))[1];
+	}
+
+	public static inline function i64ToDouble( low : Int, high : Int ) : Float {
+		return Global.unpack('d', Global.pack('ii', isLittleEndian ? low : high, isLittleEndian ? high : low))[1];
+	}
+
+	/**
+		Returns an Int64 representing the bytes representation of the double precision IEEE float value.
+		WARNING : for performance reason, the same Int64 value might be reused every time. Copy its low/high values before calling again.
+		We still ensure that this is safe to use in a multithread environment
+	**/
+	public static function doubleToI64( v : Float ) : Int64 {
+		var a = Global.unpack(isLittleEndian ? 'V2' : 'N2', Global.pack('d', v));
+		var i64 = i64tmp;
+		@:privateAccess i64.set_low(a[isLittleEndian ? 1 : 2]);
+		@:privateAccess i64.set_high(a[isLittleEndian ? 2 : 1]);
+
+		return i64;
+	}
+
+}

+ 55 - 0
std/php7/_std/haxe/zip/Compress.hx

@@ -0,0 +1,55 @@
+/*
+ * Copyright (C)2005-2016 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 haxe.zip;
+
+@:coreApi
+class Compress {
+
+	private var level : Int;
+
+	public function new( level : Int ) : Void {
+		this.level = level;
+	}
+
+	public function execute( src : haxe.io.Bytes, srcPos : Int, dst : haxe.io.Bytes, dstPos : Int ) : { done : Bool, read : Int, write : Int } {
+		var input = src.sub( srcPos , src.length - srcPos );
+		var data = run( input , level );
+		dst.blit( dstPos , data , 0 , data.length );
+
+		return {
+			done: true,
+			read: input.length,
+			write: data.length
+		};
+	}
+
+	public function setFlushMode( f : FlushMode ) : Void {
+	}
+
+	public function close() : Void {
+	}
+
+	public static function run( s : haxe.io.Bytes, level : Int ) : haxe.io.Bytes {
+		var c = untyped __call__("gzcompress", s.toString(), level);
+		return haxe.io.Bytes.ofString(c);
+	}
+}

+ 45 - 0
std/php7/_std/haxe/zip/Uncompress.hx

@@ -0,0 +1,45 @@
+/*
+ * Copyright (C)2005-2012 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 haxe.zip;
+
+class Uncompress {
+
+	public function new( ?windowBits : Int ) {
+		throw "Not implemented for this platform";
+	}
+
+	public function execute( src : haxe.io.Bytes, srcPos : Int, dst : haxe.io.Bytes, dstPos : Int ) : { done : Bool, read : Int, write : Int } {
+		return null;
+	}
+
+	public function setFlushMode( f : FlushMode ) {
+	}
+
+	public function close() {
+	}
+
+	public static function run( src : haxe.io.Bytes, ?bufsize : Int ) : haxe.io.Bytes {
+		var c = untyped __call__("gzuncompress", src.toString());
+		return haxe.io.Bytes.ofString(c);
+	}
+
+}

+ 112 - 0
std/php7/_std/sys/FileSystem.hx

@@ -0,0 +1,112 @@
+/*
+ * Copyright (C)2005-2016 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 sys;
+
+import php.*;
+import haxe.io.Path;
+
+private enum FileKind {
+	kdir;
+	kfile;
+	kother( k : String );
+}
+
+@:coreApi
+class FileSystem {
+
+	public static inline function exists( path : String ) : Bool {
+		return Global.file_exists(path);
+	}
+
+	public static inline function rename( path : String, newPath : String ) : Void {
+		Global.rename(path, newPath);
+	}
+
+	public static function stat( path : String ) : FileStat {
+		var info = Global.stat(path);
+		if (info == false) throw 'Unable to stat $path';
+		var info:NativeArray = info;
+
+		return {
+			gid   : info['gid'],
+			uid   : info['uid'],
+			atime : Date.fromTime(info['atime'] * 1000),
+			mtime : Date.fromTime(info['mtime'] * 1000),
+			ctime : Date.fromTime(info['ctime'] * 1000),
+			dev   : info['dev'],
+			ino   : info['ino'],
+			nlink : info['nlink'],
+			rdev  : info['rdev'],
+			size  : info['size'],
+			mode  : info['mode']
+		};
+	}
+
+	public static inline function fullPath( relPath : String ) : String {
+		return (Syntax.binop(Global.realpath(relPath), "?:", null));
+	}
+
+	public static function absolutePath ( relPath : String ) : String {
+		if (Path.isAbsolute(relPath)) return relPath;
+		return Path.join([Sys.getCwd(), relPath]);
+	}
+
+	static function kind( path : String ) : FileKind {
+		var kind = Global.filetype(path);
+		if (kind == false) throw 'Failed to check file type $path';
+
+		switch(kind) {
+			case "file": return kfile;
+			case "dir": return kdir;
+			default: return kother(kind);
+		}
+	}
+
+	public static inline function isDirectory( path : String ) : Bool {
+		return Global.is_dir(path);
+	}
+
+	public static inline function createDirectory( path : String ) : Void {
+		Global.mkdir(path, 493, true);
+	}
+
+	public static inline function deleteFile( path : String ) : Void {
+		Syntax.suppress(Global.unlink(path));
+	}
+
+	public static inline function deleteDirectory( path : String ) : Void {
+		Syntax.suppress(Global.rmdir(path));
+	}
+
+	public static function readDirectory( path : String ) : Array<String> {
+		var list = [];
+		var dir = Global.opendir(path);
+		var file;
+		while ((file = Global.readdir(dir)) != false) {
+			if (file != '.' && file != '..') {
+				list.push(file);
+			}
+		}
+		Global.closedir(dir);
+        return list;
+	}
+}

+ 237 - 0
std/php7/_std/sys/db/Mysql.hx

@@ -0,0 +1,237 @@
+/*
+ * Copyright (C)2005-2016 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 sys.db;
+
+import php.*;
+import sys.db.*;
+import php.db.*;
+import php.db.Mysqli_result;
+
+@:coreApi class Mysql {
+	public static function connect(
+		params : {
+			host : String,
+			?port : Int,
+			user : String,
+			pass : String,
+			?socket : String,
+			database : String
+		}
+	) : Connection {
+		return new MysqlConnection(params);
+	}
+}
+
+private class MysqlConnection implements Connection {
+	var db : Mysqli;
+
+	public function new(
+		params : {
+			host : String,
+			?port : Int,
+			user : String,
+			pass : String,
+			?socket : String,
+			database : String
+		}
+	) : Void {
+		if (params.port == null) params.port = Std.parseInt(Global.ini_get('mysqli.default_port'));
+		if (params.socket == null) params.socket = Global.ini_get('mysqli.default_socket');
+
+		db = new Mysqli(params.host, params.user, params.pass, params.database, params.port, params.socket);
+	}
+
+	public function request( s : String ) : ResultSet {
+		var result = db.query(s);
+		if (result == false) throw 'Failed to perform db query';
+		if (result == true) return null;
+
+		return new MysqlResultSet(result);
+	}
+
+	public function close() : Void {
+		close();
+	}
+
+	public function escape( s : String ) : String {
+		return db.escape_string(s);
+	}
+
+	public function quote( s : String ) : String {
+		return "'" + db.escape_string(s) + "'";
+	}
+
+	public function addValue( s : StringBuf, v : Dynamic ) : Void {
+		if (Global.is_int(v)
+		|| Global.is_null(v)) {
+			s.add(v);
+		} else if (Global.is_bool(v)) {
+			s.add(v ? 1 : 0);
+		} else {
+			s.add(quote(Std.string(v)));
+		}
+	}
+
+	public function lastInsertId() : Int {
+		return db.insert_id;
+	}
+
+	public function dbName() : String {
+		return 'MySQL';
+	}
+
+	public function startTransaction() : Void {
+		var success = db.begin_transaction();
+		if (!success) throw 'Failed to start transaction';
+	}
+
+	public function commit() : Void {
+		var success = db.commit();
+		if (!success) throw 'Failed to commit transaction';
+	}
+
+	public function rollback() : Void {
+		var success = db.rollback();
+		if (!success) throw 'Failed to rollback transaction';
+	}
+
+}
+
+private class MysqlResultSet implements ResultSet {
+	static var hxAnonClassName = Boot.getHxAnon().phpClassName;
+
+	public var length(get,null) : Int;
+	public var nfields(get,null) : Int;
+
+	var result:Mysqli_result;
+	var fetchedRow:NativeAssocArray<Scalar>;
+	var fieldsInfo:NativeAssocArray<MysqliFieldInfo>;
+
+	public function new( result:Mysqli_result ) {
+		this.result = result;
+	}
+
+	public function hasNext() : Bool {
+		if (fetchedRow == null) fetchNext();
+		return fetchedRow != null;
+	}
+
+	public function next() : Dynamic {
+		if (fetchedRow == null) fetchNext();
+		return withdrawFetched();
+	}
+
+	public function results() : List<Dynamic> {
+		var list = new List();
+
+		result.data_seek(0);
+		var row = result.fetch_object(hxAnonClassName);
+		while (row != null) {
+			row = correctObjectTypes(row);
+			list.add(row);
+			row = result.fetch_object(hxAnonClassName);
+		}
+
+		return list;
+	}
+
+	public function getResult( n : Int ) : String {
+		if (fetchedRow == null) fetchNext();
+		return Global.array_values(fetchedRow)[n];
+	}
+
+	public function getIntResult( n : Int ) : Int {
+		return Syntax.int(getResult(n));
+	}
+
+	public function getFloatResult( n : Int ) : Float {
+		return Syntax.float(getResult(n));
+	}
+
+	public function getFieldsNames() : Null<Array<String>> {
+		var fields = result.fetch_fields();
+		return [for (field in fields) field.name];
+	}
+
+	function fetchNext() {
+		var row = result.fetch_assoc();
+		if (row != null) fetchedRow = correctArrayTypes(row);
+	}
+
+	function withdrawFetched() : Dynamic {
+		if (fetchedRow == null) return null;
+		return Boot.createAnon(fetchedRow);
+	}
+
+	function correctArrayTypes(row:NativeAssocArray<String>):NativeAssocArray<Scalar> {
+		var fieldsInfo = getFieldsInfo();
+		Syntax.foreach(row, function(field:String, value:String) {
+			row[field] = correctType(value, fieldsInfo[field].type);
+		});
+		return cast row;
+	}
+
+	function correctObjectTypes(row:{}):{} {
+		var fieldsInfo = getFieldsInfo();
+		Syntax.foreach(row, function(field:String, value:String) {
+			value = correctType(value, fieldsInfo[field].type);
+			Syntax.setField(row, field, value);
+		});
+		return row;
+	}
+
+	inline function getFieldsInfo():NativeAssocArray<MysqliFieldInfo> {
+		if (fieldsInfo == null) {
+			fieldsInfo = cast Syntax.arrayDecl();
+			Syntax.foreach(result.fetch_fields(), function(_, info) {
+				fieldsInfo[info.name] = info;
+			});
+		}
+		return fieldsInfo;
+	}
+
+	function correctType(value:String, type:Int):Scalar {
+		if (value == null) return null;
+		if (
+			type == Const.MYSQLI_TYPE_BIT
+			|| type == Const.MYSQLI_TYPE_TINY
+			|| type == Const.MYSQLI_TYPE_SHORT
+			|| type == Const.MYSQLI_TYPE_LONG
+			|| type == Const.MYSQLI_TYPE_INT24
+			|| type == Const.MYSQLI_TYPE_CHAR
+		) {
+			return Syntax.int(value);
+		}
+		if (
+			type == Const.MYSQLI_TYPE_DECIMAL
+			|| type == Const.MYSQLI_TYPE_NEWDECIMAL
+			|| type == Const.MYSQLI_TYPE_FLOAT
+			|| type == Const.MYSQLI_TYPE_DOUBLE
+		) {
+			return Syntax.float(value);
+		}
+		return value;
+	}
+
+	function get_length() return result.num_rows;
+	function get_nfields() return result.field_count;
+}

+ 191 - 0
std/php7/_std/sys/db/Sqlite.hx

@@ -0,0 +1,191 @@
+/*
+ * Copyright (C)2005-2016 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 sys.db;
+
+import php.*;
+import php.db.*;
+import sys.db.*;
+
+@:coreApi class Sqlite {
+	public static function open( file:String ) : Connection {
+		return new SQLiteConnection(file);
+	}
+}
+
+private class SQLiteConnection implements Connection {
+	var db:SQLite3;
+
+	public function new( file:String ) {
+		db = new SQLite3('sqlite:$file');
+		db.enableExceptions(true);
+	}
+
+	public function request( s : String ) : ResultSet {
+		var result = db.query(s);
+		return new SQLiteResultSet(result);
+	}
+
+	public function close() : Void {
+		db.close();
+	}
+
+	public function escape( s : String ) : String {
+		return SQLite3.escapeString(s);
+	}
+
+	public function quote( s : String ) : String {
+		return "'" + SQLite3.escapeString(s) + "'";
+	}
+
+	public function addValue( s : StringBuf, v : Dynamic ) : Void {
+		if (Global.is_int(v) || Global.is_null(v)) {
+			s.add(v);
+		} else if (Global.is_bool(v)) {
+			s.add(v ? 1 : 0);
+		} else {
+			s.add(quote(Std.string(v)));
+		}
+	}
+
+	public function lastInsertId() : Int {
+		return Syntax.int(db.lastInsertRowID());
+	}
+
+	public function dbName() : String {
+		return 'SQLite';
+	}
+
+	public function startTransaction() : Void {
+		db.query('BEGIN TRANSACTION');
+	}
+
+	public function commit() : Void {
+		db.query('COMMIT');
+	}
+
+	public function rollback() : Void {
+		db.query('ROLLBACK');
+	}
+}
+
+private class SQLiteResultSet implements ResultSet {
+	public var length(get,null) : Int;
+	public var nfields(get,null) : Int;
+
+	var _length : Int = 0;
+	var _nfields : Int = 0;
+
+	var loaded:Bool = false;
+	var currentIndex:Int = 0;
+	var rows:NativeIndexedArray<NativeAssocArray<Scalar>>;
+	var result:SQLite3Result;
+	var fetchedRow:NativeArray;
+	var fieldsInfo:NativeAssocArray<Int>;
+
+	public function new( result:SQLite3Result ) {
+		this.result = result;
+	}
+
+	public function hasNext() : Bool {
+		if (!loaded) load();
+		return currentIndex < _length;
+	}
+
+	public function next() : Dynamic {
+		if (!loaded) load();
+		var next:Dynamic = rows[currentIndex++];
+		return Boot.createAnon(correctArrayTypes(next));
+	}
+
+	public function results() : List<Dynamic> {
+		if (!loaded) load();
+		var list = new List();
+		Syntax.foreach(rows, function(_, row) list.add(Boot.createAnon(correctArrayTypes(row))));
+		return list;
+	}
+
+	public function getResult( n : Int ) : String {
+		if (!loaded) load();
+		if (!hasNext()) return null;
+		return Global.array_values(rows[currentIndex])[n];
+	}
+
+	public function getIntResult( n : Int ) : Int {
+		return Syntax.int(getResult(n));
+	}
+
+	public function getFloatResult( n : Int ) : Float {
+		return Syntax.float(getResult(n));
+	}
+
+	public function getFieldsNames() : Null<Array<String>> {
+		var fieldsInfo = getFieldsInfo();
+		return Global.array_keys(fieldsInfo);
+	}
+
+	function correctArrayTypes(row:NativeAssocArray<String>):NativeAssocArray<Scalar> {
+		var fieldsInfo = getFieldsInfo();
+		Syntax.foreach(row, function(field:String, value:String) {
+			row[field] = correctType(value, fieldsInfo[field]);
+		});
+		return cast row;
+	}
+
+	inline function getFieldsInfo():NativeAssocArray<Int> {
+		if (fieldsInfo == null) {
+			fieldsInfo = cast Syntax.arrayDecl();
+			for(i in 0...nfields) {
+				fieldsInfo[result.columnName(i)] = result.columnType(i);
+			}
+		}
+		return fieldsInfo;
+	}
+
+	function load() {
+		loaded = true;
+		_nfields = result.numColumns();
+		getFieldsInfo();
+		fetchAll();
+	}
+
+	function correctType(value:String, type:Int):Scalar {
+		if (value == null) return null;
+		if (type == Const.SQLITE3_INTEGER) return Syntax.int(value);
+		if (type == Const.SQLITE3_FLOAT) return Syntax.float(value);
+		return value;
+	}
+
+	function fetchAll() {
+		rows = Syntax.arrayDecl();
+		var index = 0;
+		var row = result.fetchArray(Const.SQLITE3_ASSOC);
+		while(row != false) {
+			rows[index] = correctArrayTypes(row);
+			row = result.fetchArray(Const.SQLITE3_ASSOC);
+			index++;
+		}
+		_length = index;
+	}
+
+	function get_length() return _length;
+	function get_nfields() return _nfields;
+}

+ 63 - 0
std/php7/_std/sys/io/File.hx

@@ -0,0 +1,63 @@
+/*
+ * Copyright (C)2005-2016 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 sys.io;
+
+enum FileHandle {
+}
+
+@:coreApi class File {
+
+	public static function getContent( path : String ) : String {
+		return untyped __call__("file_get_contents", path);
+	}
+
+	public static function getBytes( path : String ) : haxe.io.Bytes {
+		return haxe.io.Bytes.ofString(getContent(path));
+	}
+
+	public static function saveContent( path : String, content : String) : Void {
+		untyped __call__("file_put_contents", path, content);
+	}
+
+	public static function saveBytes( path : String, bytes : haxe.io.Bytes ) : Void {
+		var f = write(path);
+		f.write(bytes);
+		f.close();
+	}
+
+	public static function read( path : String, binary : Bool = true ) : FileInput {
+		return untyped new FileInput(__call__('fopen', path, binary ? "rb" : "r"));
+	}
+
+	public static function write( path : String, binary : Bool = true ) : FileOutput {
+		return untyped new FileOutput(untyped __call__('fopen', path, binary ? "wb" : "w"));
+	}
+
+	public static function append( path : String, binary : Bool = true ) : FileOutput {
+		return untyped new FileOutput(untyped __call__('fopen', path, binary ? "ab" : "a"));
+	}
+
+	public static function copy( srcPath : String, dstPath : String ) : Void {
+		untyped __call__("copy", srcPath, dstPath);
+	}
+
+}

+ 82 - 0
std/php7/_std/sys/io/FileInput.hx

@@ -0,0 +1,82 @@
+/*
+ * Copyright (C)2005-2016 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 sys.io;
+import haxe.io.Eof;
+
+@:coreApi
+class FileInput extends haxe.io.Input {
+
+	private var __f : File.FileHandle;
+
+	function new(f:File.FileHandle) : Void {
+		__f = f;
+	}
+
+	public override function readByte() : Int {
+		var r = untyped __call__('fread', __f, 1);
+		if(untyped __call__('feof', __f)) return throw new haxe.io.Eof();
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		return untyped __call__('ord', r);
+	}
+
+	public override function readBytes( s : haxe.io.Bytes, p : Int, l : Int ) : Int {
+		if(untyped __call__('feof', __f)) return throw new haxe.io.Eof();
+		var r : String = untyped __call__('fread', __f, l);
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		var b = haxe.io.Bytes.ofString(r);
+		s.blit(p, b, 0, r.length);
+		return r.length;
+	}
+
+	public override function close() : Void {
+		super.close();
+		if(__f != null)	untyped __call__('fclose', __f);
+	}
+
+	public function seek( p : Int, pos : FileSeek ) : Void {
+		var w;
+		switch( pos ) {
+			case SeekBegin: w = untyped __php__('SEEK_SET');
+			case SeekCur  : w = untyped __php__('SEEK_CUR');
+			case SeekEnd  : w = untyped __php__('SEEK_END');
+		}
+		var r = untyped __call__('fseek', __f, p, w);
+		if(untyped __physeq__(r, false)) throw haxe.io.Error.Custom('An error occurred');
+	}
+
+	public function tell() : Int {
+		var r = untyped __call__('ftell', __f);
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		return cast r;
+	}
+
+	public function eof() : Bool {
+		return untyped __call__('feof', __f);
+	}
+
+	override function readLine() : String {
+		var r : String = untyped __call__('fgets', __f);
+		if (untyped __physeq__(false, r))
+			throw new Eof();
+		return untyped __call__("rtrim", r, "\r\n");
+	}
+}

+ 72 - 0
std/php7/_std/sys/io/FileOutput.hx

@@ -0,0 +1,72 @@
+/*
+ * Copyright (C)2005-2016 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 sys.io;
+
+@:coreApi
+class FileOutput extends haxe.io.Output {
+	private var __f : File.FileHandle;
+
+	function new(f:File.FileHandle) : Void {
+		__f = f;
+	}
+
+	public override function writeByte( c : Int ) : Void {
+		var r = untyped __call__('fwrite', __f, __call__('chr', c));
+		if(untyped __physeq__(r, false)) throw haxe.io.Error.Custom('An error occurred');
+	}
+
+	public override function writeBytes( b : haxe.io.Bytes, p : Int, l : Int ) : Int {
+		var s = b.getString(p, l);
+		if(untyped __call__('feof', __f)) return throw new haxe.io.Eof();
+		var r = untyped __call__('fwrite', __f, s, l);
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		return r;
+	}
+
+	public override function flush() : Void {
+		var r = untyped __call__('fflush', __f);
+		if(untyped __physeq__(r, false)) throw haxe.io.Error.Custom('An error occurred');
+	}
+
+	public override function close() : Void {
+		super.close();
+		if(__f != null)	untyped __call__('fclose', __f);
+	}
+
+	public function seek( p : Int, pos : FileSeek ) : Void {
+		var w;
+		switch( pos ) {
+			case SeekBegin: w = untyped __php__('SEEK_SET');
+			case SeekCur  : w = untyped __php__('SEEK_CUR');
+			case SeekEnd  : w = untyped __php__('SEEK_END');
+		}
+		var r = untyped __call__('fseek', __f, p, w);
+		if(untyped __physeq__(r, false)) throw haxe.io.Error.Custom('An error occurred');
+	}
+
+	public function tell() : Int {
+		var r = untyped __call__('ftell', __f);
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		return cast r;
+	}
+
+}

+ 213 - 0
std/php7/_std/sys/io/Process.hx

@@ -0,0 +1,213 @@
+/*
+ * Copyright (C)2005-2016 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 sys.io;
+
+import php.*;
+import haxe.io.*;
+
+using StringTools;
+using php.Global;
+
+@:forward(iterator)
+private abstract ProcessPipes(NativeIndexedArray<Resource>) from NativeIndexedArray<Resource> to NativeIndexedArray<Resource> {
+	public var stdin (get,never) : Resource;
+	public var stdout (get,never) : Resource;
+	public var stderr (get,never) : Resource;
+
+	inline function get_stdin() return this[0];
+	inline function get_stdout() return this[1];
+	inline function get_stderr() return this[2];
+}
+
+private class ReadablePipe extends Input {
+	var pipe : Resource;
+	var tmpBytes : Bytes;
+
+	public function new(pipe:Resource) {
+		this.pipe = pipe;
+		tmpBytes = Bytes.alloc(1);
+	}
+
+	override public function close() : Void {
+		pipe.fclose();
+	}
+
+	override public function readByte() : Int {
+		if (readBytes(tmpBytes, 0, 1) == 0) throw Error.Blocked;
+		return tmpBytes.get(0);
+	}
+
+	override public function readBytes( s:Bytes, pos:Int, len:Int ) : Int {
+		if(pipe.feof()) throw new Eof();
+
+		var result = pipe.fread(len);
+		if(result == "") throw new Eof();
+		if(result == false) return throw Error.Custom('Failed to read process output');
+		var result:String = result;
+
+		var bytes = Bytes.ofString(result);
+		s.blit(pos, bytes, 0, result.length);
+		return result.length;
+	}
+}
+
+private class WritablePipe extends Output {
+	var pipe : Resource;
+	var tmpBytes : Bytes;
+
+	public function new(pipe:Resource) {
+		this.pipe = pipe;
+		tmpBytes = Bytes.alloc(1);
+	}
+
+	override public function close() : Void {
+		pipe.fclose();
+	}
+
+	override public function writeByte(c:Int) : Void {
+		tmpBytes.set(0, c);
+		writeBytes(tmpBytes, 0, 1);
+	}
+
+	override public function writeBytes( b : Bytes, pos : Int, l : Int ) : Int {
+		var s = b.getString(pos, l);
+		if(pipe.feof()) throw new Eof();
+
+		var result = Global.fwrite(pipe, s, l);
+		if(result == false) throw Error.Custom('Failed to write to process input');
+		return result;
+	}
+}
+
+class Process {
+	/**
+		Standard output. The output stream where a process writes its output data.
+	**/
+	public var stdout(default, null) : Input;
+
+	/**
+		Standard error. The output stream to output error messages or diagnostics.
+	**/
+	public var stderr(default, null) : Input;
+
+	/**
+		Standard input. The stream data going into a process.
+	**/
+	public var stdin(default, null) : Output;
+
+	var process : Resource;
+	var pipes : ProcessPipes;
+	var pid : Int = -1;
+	var running : Bool = true;
+	var _exitCode : Int = -1;
+
+	/**
+		Construct a `Process` object, which run the given command immediately.
+
+		Command arguments can be passed in two ways: 1. using `args`, 2. appending to `cmd` and leaving `args` as `null`.
+
+		 1. When using `args` to pass command arguments, each argument will be automatically quoted, and shell meta-characters will be escaped if needed.
+		`cmd` should be an executable name that can be located in the `PATH` environment variable, or a path to an executable.
+
+		 2. When `args` is not given or is `null`, command arguments can be appended to `cmd`. No automatic quoting/escaping will be performed. `cmd` should be formatted exactly as it would be when typed at the command line.
+		It can run executables, as well as shell commands that are not executables (e.g. on Windows: `dir`, `cd`, `echo` etc).
+
+		`close()` should be called when the `Process` is no longer used.
+	*/
+	public function new( cmd : String, ?args : Array<String> ) : Void {
+		var descriptors = Syntax.arrayDecl(
+			Syntax.arrayDecl('pipe', 'r'),
+			Syntax.arrayDecl('pipe', 'w'),
+			Syntax.arrayDecl('pipe', 'w')
+		);
+		var result = buildCmd(cmd, args).proc_open(descriptors, pipes);
+		if (result == false) throw Error.Custom('Failed to start process: $cmd');
+		process = result;
+
+		updateStatus();
+
+		stdin = new WritablePipe(pipes.stdin);
+		stdout = new ReadablePipe(pipes.stdout);
+		stderr = new ReadablePipe(pipes.stderr);
+	}
+
+	/**
+		Return the process ID.
+	*/
+	public function getPid() : Int {
+		return pid;
+	}
+
+	/**
+		Block until the process exits and return the exit code of the process.
+		If the process has already exited, return the exit code immediately.
+	*/
+	public function exitCode() : Int {
+		while (running) {
+			var arr = Syntax.arrayDecl(process);
+			Syntax.suppress(Global.stream_select(arr, arr, arr, null));
+			updateStatus();
+		}
+		return _exitCode;
+	}
+
+	/**
+		Close the process handle and release the associated resources.
+		All `Process` fields should not be used after `close()` is called.
+	*/
+	public function close() : Void {
+		if (!running) return;
+
+		for (pipe in pipes) Global.fclose(pipe);
+		process.proc_close();
+	}
+
+	/**
+		Kill the process.
+	*/
+	public function kill() : Void {
+		process.proc_terminate();
+	}
+
+	function buildCmd( cmd:String, ?args:Array<String> ) : String {
+		if (args == null) return cmd;
+
+		return switch (Sys.systemName()) {
+			case "Windows":
+				[cmd.replace("/", "\\")].concat(args).map(StringTools.quoteWinArg.bind(_, true)).join(" ");
+			case _:
+				[cmd].concat(args).map(StringTools.quoteUnixArg).join(" ");
+		}
+	}
+
+	function updateStatus() : Void {
+		if (!running) return;
+
+		var status = process.proc_get_status();
+		if (status == false) throw Error.Custom('Failed to obtain process status');
+		var status:NativeAssocArray<Scalar> = status;
+
+		pid = status['pid'];
+		running = status['running'];
+		_exitCode = status['exitcode'];
+	}
+}

+ 58 - 0
std/php7/_std/sys/net/Host.hx

@@ -0,0 +1,58 @@
+/*
+ * Copyright (C)2005-2016 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 sys.net;
+
+@:coreApi
+class Host {
+
+	public var host(default,null) : String;
+
+	private var _ip : String;
+	public var ip(default,null) : Int;
+
+	public function new( name : String ) : Void {
+		host = name;
+		if(~/^(\d{1,3}\.){3}\d{1,3}$/.match(name)) {
+		  _ip = name;
+		} else {
+			_ip = untyped __call__('gethostbyname', name);
+			if(_ip == name) {
+				ip = 0;
+				return;
+			}
+		}
+		var p = _ip.split('.');
+		ip = untyped __call__('intval', __call__('sprintf', '%02X%02X%02X%02X', p[3], p[2], p[1], p[0]), 16);
+	}
+
+	public function toString() : String {
+		return _ip;
+	}
+
+	public function reverse() : String {
+		return untyped __call__('gethostbyaddr', _ip);
+	}
+
+	public static function localhost() : String {
+		return untyped __var__('_SERVER', 'HTTP_HOST');
+	}
+}

+ 172 - 0
std/php7/_std/sys/net/Socket.hx

@@ -0,0 +1,172 @@
+/*
+ * Copyright (C)2005-2016 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 sys.net;
+
+import sys.io.File;
+
+@:coreApi
+class Socket {
+
+	private var __s : FileHandle;
+	private var protocol : String;
+	public var input(default,null) : haxe.io.Input;
+	public var output(default,null) : haxe.io.Output;
+	public var custom : Dynamic;
+
+	public function new() : Void {
+		input = untyped new sys.io.FileInput(null);
+		output = untyped new sys.io.FileOutput(null);
+		protocol = "tcp";
+	}
+
+	private function assignHandler() : Void {
+		untyped input.__f = __s;
+		untyped output.__f = __s;
+	}
+
+	public function close() : Void {
+		untyped __call__('fclose', __s);
+		untyped {
+			input.__f = null;
+			output.__f = null;
+		}
+		input.close();
+		output.close();
+	}
+
+	public function read() : String {
+		var b = '';
+		untyped __php__("while (!feof($this->__s)) $b .= fgets($this->__s)");
+		return b;
+	}
+
+	public function write( content : String ) : Void {
+		return untyped __call__('fwrite', __s, content);
+	}
+
+	public function connect(host : Host, port : Int) : Void {
+		var errs = null;
+		var errn = null;
+		var r = untyped __call__('stream_socket_client', protocol + '://' +host._ip + ':' + port, errn, errs);
+		Socket.checkError(r, errn, errs);
+		__s = cast r;
+		assignHandler();
+	}
+
+	public function listen(connections : Int) : Void {
+		throw "Not implemented";
+/* TODO: ??????
+		var r = untyped __call__('socket_listen', __s, connections);
+		checkError(r);
+*/
+	}
+
+	public function shutdown( read : Bool, write : Bool ) : Void {
+		var r;
+		if(untyped __call__("function_exists", "stream_socket_shutdown")) {
+			var rw = read && write ? 2 : (write ? 1 : (read ? 0 : 2));
+			r = untyped __call__('stream_socket_shutdown', __s, rw);
+		} else {
+			r = untyped __call__('fclose', __s);
+		}
+		checkError(r, 0, 'Unable to Shutdown');
+	}
+
+	public function bind(host : Host, port : Int) : Void {
+		var errs = null;
+		var errn = null;
+		var r = untyped __call__('stream_socket_server', protocol + '://' +host._ip + ':' + port, errn, errs, (protocol=="udp") ? __php__('STREAM_SERVER_BIND') : __php__('STREAM_SERVER_BIND | STREAM_SERVER_LISTEN'));
+		Socket.checkError(r, errn, errs);
+		__s = cast r;
+		assignHandler();
+	}
+
+	public function accept() : Socket {
+		var r = untyped __call__('stream_socket_accept', __s);
+		checkError(r, 0, 'Unable to accept connections on socket');
+		var s = new Socket();
+		s.__s = cast r;
+		s.assignHandler();
+		return s;
+	}
+
+	private function hpOfString(s : String) : { host : Host, port : Int } {
+		var parts = s.split(':');
+		if(parts.length == 2) {
+			return { host : new Host(parts[0]), port : Std.parseInt(parts[1]) };
+		} else {
+			return { host : new Host(parts[1].substr(2)), port : Std.parseInt(parts[2]) };
+		}
+	}
+
+	public function peer() : { host : Host, port : Int } {
+		var r : String = untyped __call__('stream_socket_get_name', __s, true);
+		checkError(cast r, 0, 'Unable to retrieve the peer name');
+		return hpOfString(r);
+	}
+
+	public function host() : { host : Host, port : Int } {
+		var r : String = untyped __call__('stream_socket_get_name', __s, false);
+		checkError(cast r, 0, 'Unable to retrieve the host name');
+		return hpOfString(r);
+	}
+
+	public function setTimeout( timeout : Float ) : Void {
+		var s = Std.int(timeout);
+		var ms = Std.int((timeout-s)*1000000);
+		var r = untyped __call__('stream_set_timeout', __s, s, ms);
+		checkError(r, 0, 'Unable to set timeout');
+	}
+
+	public function setBlocking( b : Bool ) : Void {
+		var r = untyped __call__('stream_set_blocking', __s, b);
+		checkError(r, 0, 'Unable to block');
+	}
+
+	public function setFastSend( b : Bool ) : Void {
+		throw "Not implemented";
+	}
+
+	public function waitForRead() : Void {
+		select([this],null,null);
+	}
+
+	private static function checkError(r : Bool, code : Int, msg : String) : Void {
+		if(!untyped __physeq__(r, false)) return;
+		throw haxe.io.Error.Custom('Error ['+code+']: ' +msg);
+	}
+
+	private static function getType(isUdp : Bool) : Int {
+		return isUdp ? untyped __php__('SOCK_DGRAM') : untyped __php__('SOCK_STREAM');
+	}
+
+	private static function getProtocol(protocol : String) : Int {
+		return untyped __call__('getprotobyname', protocol);
+ 	}
+
+	public static function select(read : Array<Socket>, write : Array<Socket>, others : Array<Socket>, ?timeout : Float) : { read: Array<Socket>,write: Array<Socket>,others: Array<Socket> }
+	{
+		throw "Not implemented";
+		return null;
+	}
+
+}

+ 71 - 0
std/php7/db/Mysqli.hx

@@ -0,0 +1,71 @@
+package php.db;
+
+import haxe.extern.*;
+import php.*;
+import haxe.Constraints.Function;
+
+/**
+    @see http://php.net/manual/en/class.mysqli.php
+**/
+@:native('Mysqli')
+extern class Mysqli {
+    var affected_rows (default,null) : Int;
+    var client_info (default,null) : String;
+    var client_version (default,null) : Int;
+    var connect_errno (default,null) : Int;
+    var connect_error (default,null) : String;
+    var errno (default,null) : Int;
+    var error_list (default,null) : NativeAssocArray<Scalar>;
+    var error (default,null) : String;
+    var field_count (default,null) : Int;
+    var host_info (default,null) : String;
+    var protocol_version (default,null) : String;
+    var server_info (default,null) : String;
+    var server_version (default,null) : Int;
+    var info (default,null) : String;
+    var insert_id (default,null) : EitherType<Int,String>;
+    var sqlstate (default,null) : String;
+    var thread_id (default,null) : Int;
+    var warning_count (default,null) : Int;
+
+    static function poll( read:Ref<NativeArray> , error:Ref<NativeArray> , reject:Ref<NativeArray> , sec:Int, ?usec:Int ) : Int;
+
+    function new( ?host:String, ?username:String, ?passwd:String, dbname:String = "", ?port:Int, ?socket:String ) : Void;
+    function autocommit( mode:Bool ) : Bool;
+    function begin_transaction( ?flags:Int, ?name:String ) : Bool;
+    function change_user( user:String, password:String, database:String ) : Bool;
+    function character_set_name() : String;
+    function close() : Bool;
+    function commit( ?flags:Int, ?name:String ) : Bool;
+    function debug( message:String ) : Bool;
+    function dump_debug_info() : Bool;
+    function get_charset() : {charset:String, collation:String, dir:String, min_length:Int, number:Int, state:Int};
+    function get_client_info() : String;
+    function get_connection_stats() : Bool;
+    function get_warnings() : Mysqli_warning;
+    function init() : Mysqli;
+    function kill( processid:Int ) : Bool;
+    function more_results() : Bool;
+    function multi_query( query:String ) : Bool;
+    function next_result() : Bool;
+    function options( option:Int , value:Scalar ) : Bool;
+    function ping() : Bool;
+    function prepare( query:String ) : Mysqli_stmt;
+    function query( query:String, ?resultmode:Int ) : EitherType<Bool,Mysqli_result>;
+    function real_connect( ?host:String, ?username:String, ?passwd:String, ?dbname:String, ?port:Int, ?socket:String, ?flags:Int ) : Bool;
+    function escape_string( escapestr:String ) : String;
+    function real_query( query:String ) : Bool;
+    function reap_async_query() : Mysqli_result;
+    function refresh( options:Int ) : Bool;
+    function rollback( ?flags:Int, ?name:String ) : Bool;
+    function rpl_query_type( query:String ) : Int;
+    function select_db( dbname:String ) : Bool;
+    function send_query( query:String ) : Bool;
+    function set_charset( charset:String ) : Bool;
+    function set_local_infile_handler( read_func:Function ) : Bool;
+    function ssl_set( key:String, cert:String, ca:String, capath:String, cipher:String) : Bool;
+    function stat() : String;
+    function stmt_init() : Mysqli_stmt;
+    function store_result( ?option:Int ) : Mysqli_result;
+    function use_result() : Mysqli_result;
+}

+ 16 - 0
std/php7/db/Mysqli_driver.hx

@@ -0,0 +1,16 @@
+package php.db;
+
+import php.NativeArray;
+
+@:native('Mysqli_driver')
+extern class Mysqli_driver {
+    var client_info (default,null) : String ;
+    var client_version (default,null) : String ;
+    var driver_version (default,null) : String ;
+    var embedded (default,null) : String ;
+    var reconnect (default,null) : Bool ;
+    var report_mode (default,null) : Int ;
+
+    function embedded_server_end() : Void;
+    function embedded_server_start( start:Bool, arguments:NativeArray, groups:NativeArray ) : Bool;
+}

+ 40 - 0
std/php7/db/Mysqli_result.hx

@@ -0,0 +1,40 @@
+package php.db;
+
+import php.*;
+import haxe.extern.*;
+
+/**
+    @see http://php.net/manual/en/class.mysqli-result.php
+**/
+@:native('Myslqi_result')
+extern class Mysqli_result implements Traversable {
+    var current_field  (default,null) : Int;
+    var field_count (default,null) : Int;
+    var lengths (default,null) : EitherType<Bool, NativeIndexedArray<Int>>;
+    var num_rows (default,null) : Int;
+
+    function data_seek( offset:Int ) : Bool;
+    function fetch_all( ?resulttype:Int ) : NativeArray;
+    function fetch_array( ?resulttype:Int ) : NativeArray;
+    function fetch_assoc() : NativeAssocArray<String>;
+    function fetch_field_direct( fieldnr:Int ) : MysqliFieldInfo;
+    function fetch_field() : MysqliFieldInfo;
+    function fetch_fields() : NativeIndexedArray<MysqliFieldInfo>;
+    function fetch_object( ?class_name:String = "stdClass", ?params:NativeArray ) : {};
+    function fetch_row() : NativeIndexedArray<String>;
+    function field_seek( fieldnr:Int ) : Bool;
+    function free() : Void;
+}
+
+typedef MysqliFieldInfo = {
+    name : String,
+    orgname : String,
+    table : String,
+    orgtable : String,
+    max_length : Int,
+    length : Int,
+    charsetnr : Int,
+    flags : Int,
+    type : Int,
+    decimals : Int
+}

+ 35 - 0
std/php7/db/Mysqli_stmt.hx

@@ -0,0 +1,35 @@
+package php.db;
+
+import haxe.extern.*;
+import php.*;
+
+@:native('Mysqli_stmt')
+extern class Mysqli_stmt {
+    var affected_rows (default,null) : Int;
+    var errno (default,null) : Int;
+    var error_list (default,null) : NativeArray;
+    var error (default,null) : String;
+    var field_count (default,null) : Int;
+    var insert_id (default,null) : Int;
+    var num_rows (default,null) : Int;
+    var param_count (default,null) : Int;
+    var sqlstate (default,null) : String;
+
+    function new( link:Mysqli, ?query:String ) : Void;
+    function attr_get( attr:Int ) : Int;
+    function attr_set( attr:Int , mode:Int ) : Bool;
+    function bind_param( types:String , var1:Ref<Dynamic>, args:Rest<Ref<Dynamic>> ) : Bool;
+    function bind_result( var1:Ref<Dynamic>, args:Rest<Ref<Dynamic>> ) : Bool;
+    function close() : Bool;
+    function data_seek( offset:Int ) : Void;
+    function execute() : Bool;
+    function fetch() : Bool;
+    function free_result() : Void;
+    function get_result() : Mysqli_result;
+    function get_warnings( stmt:Mysqli_stmt ) : {};
+    function prepare( query:String ) : Bool;
+    function reset() : Bool;
+    function result_metadata() : Mysqli_result;
+    function send_long_data( param_nr:Int , data:String ) : Bool;
+    function store_result() : Bool;
+}

+ 10 - 0
std/php7/db/Mysqli_warning.hx

@@ -0,0 +1,10 @@
+package php.db;
+
+@:native('Mysqli_warning')
+extern class Mysqli_warning {
+    var message (default,null): String;
+    var sqlstate (default,null): Dynamic;
+    var errno (default,null): Int;
+
+    function next() : Void;
+}

+ 107 - 0
std/php7/db/PDO.hx

@@ -0,0 +1,107 @@
+/*
+ * Copyright (C)2005-2016 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.db;
+
+import php.*;
+
+@:native('PDO')
+extern class PDO {
+	@:phpClassConst static var PARAM_BOOL : Int;
+	@:phpClassConst static var PARAM_NULL : Int;
+	@:phpClassConst static var PARAM_INT : Int;
+	@:phpClassConst static var PARAM_STR : Int;
+	@:phpClassConst static var PARAM_LOB : Int;
+	@:phpClassConst static var PARAM_STMT : Int;
+	@:phpClassConst static var PARAM_INPUT_OUTPUT : Int;
+	@:phpClassConst static var FETCH_LAZY : Int;
+	@:phpClassConst static var FETCH_ASSOC : Int;
+	@:phpClassConst static var FETCH_NAMED : Int;
+	@:phpClassConst static var FETCH_NUM : Int;
+	@:phpClassConst static var FETCH_BOTH : Int;
+	@:phpClassConst static var FETCH_OBJ : Int;
+	@:phpClassConst static var FETCH_BOUND : Int;
+	@:phpClassConst static var FETCH_COLUMN : Int;
+	@:phpClassConst static var FETCH_CLASS : Int;
+	@:phpClassConst static var FETCH_INTO : Int;
+	@:phpClassConst static var FETCH_FUNC : Int;
+	@:phpClassConst static var FETCH_GROUP : Int;
+	@:phpClassConst static var FETCH_UNIQUE : Int;
+	@:phpClassConst static var FETCH_KEY_PAIR : Int;
+	@:phpClassConst static var FETCH_CLASSTYPE : Int;
+	@:phpClassConst static var FETCH_SERIALIZE : Int;
+	@:phpClassConst static var FETCH_PROPS_LATE : Int;
+	@:phpClassConst static var ATTR_AUTOCOMMIT : Int;
+	@:phpClassConst static var ATTR_PREFETCH : Int;
+	@:phpClassConst static var ATTR_TIMEOUT : Int;
+	@:phpClassConst static var ATTR_ERRMODE : Int;
+	@:phpClassConst static var ATTR_SERVER_VERSION : Int;
+	@:phpClassConst static var ATTR_CLIENT_VERSION : Int;
+	@:phpClassConst static var ATTR_SERVER_INFO : Int;
+	@:phpClassConst static var ATTR_CONNECTION_STATUS : Int;
+	@:phpClassConst static var ATTR_CASE : Int;
+	@:phpClassConst static var ATTR_CURSOR_NAME : Int;
+	@:phpClassConst static var ATTR_CURSOR : Int;
+	@:phpClassConst static var ATTR_DRIVER_NAME : String;
+	@:phpClassConst static var ATTR_ORACLE_NULLS : Int;
+	@:phpClassConst static var ATTR_PERSISTENT : Int;
+	@:phpClassConst static var ATTR_STATEMENT_CLASS : Int;
+	@:phpClassConst static var ATTR_FETCH_TABLE_NAMES : Int;
+	@:phpClassConst static var ATTR_STRINGIFY_FETCHES : Int;
+	@:phpClassConst static var ATTR_EMULATE_PREPARES : Int;
+	@:phpClassConst static var ERRMODE_SILENT : Int;
+	@:phpClassConst static var ERRMODE_WARNING : Int;
+	@:phpClassConst static var ERRMODE_EXCEPTION : Int;
+	@:phpClassConst static var CASE_NATURAL : Int;
+	@:phpClassConst static var CASE_LOWER : Int;
+	@:phpClassConst static var CASE_UPPER : Int;
+	@:phpClassConst static var NULL_NATURAL : Int;
+	@:phpClassConst static var FETCH_ORI_PRIOR : Int;
+	@:phpClassConst static var FETCH_ORI_FIRST : Int;
+	@:phpClassConst static var FETCH_ORI_LAST : Int;
+	@:phpClassConst static var FETCH_ORI_ABS : Int;
+	@:phpClassConst static var FETCH_ORI_REL : Int;
+	@:phpClassConst static var CURSOR_FWDONLY : Int;
+	@:phpClassConst static var CURSOR_SCROLL : Int;
+	@:phpClassConst static var ERR_NONE : String;
+	@:phpClassConst static var PARAM_EVT_ALLOC : Int;
+	@:phpClassConst static var PARAM_EVT_FREE : Int;
+	@:phpClassConst static var PARAM_EVT_EXEC_PRE : Int;
+	@:phpClassConst static var PARAM_EVT_EXEC_POST : Int;
+	@:phpClassConst static var PARAM_EVT_FETCH_PRE : Int;
+	@:phpClassConst static var PARAM_EVT_FETCH_POST : Int;
+	@:phpClassConst static var PARAM_EVT_NORMALIZE : Int;
+
+	function new( dns : String, ?username : String, ?password : String, ?options : NativeArray) : Void;
+	function beginTransaction() : Bool;
+	function commit() : Bool;
+	function errorCode() : Dynamic;
+	function errorInfo() : NativeArray;
+	function exec(statement : String) : Int;
+	function getAttribute(attribute : Int) : Dynamic;
+	function getAvailableDrivers() : NativeArray;
+	function lastInsertId(?name : String) : String;
+	function prepare(statement : String, driver_options : NativeArray) : PDOStatement;
+	function query(statement : String, ?mode : Int) : PDOStatement;
+	function quote(String : String, ?parameter_type : Int = 2) : String;
+	function rollBack() : Bool;
+	function setAttribute(attribute : Int, value : Dynamic) : Bool;
+}

+ 8 - 0
std/php7/db/PDOException.hx

@@ -0,0 +1,8 @@
+package php.db;
+
+import php.RuntimeException;
+
+@:native('PDOException')
+extern class PDOException extends RuntimeException {
+    var errorInfo : NativeArray;
+}

+ 26 - 0
std/php7/db/PDOStatement.hx

@@ -0,0 +1,26 @@
+package php.db;
+
+import php.*;
+
+@:native('PDOStatement')
+extern class PDOStatement {
+	function bindColumn(column : Dynamic, param : Dynamic, ?type : Int, ?maxlen : Int, ?driverdata : Dynamic) : Bool;
+	function bindParam(parameter : Dynamic, variable : Dynamic, ?data_type : Int, ?length : Int, ?driver_options : Dynamic) : Bool;
+	function bindValue(parameter : Dynamic, value : Dynamic, ?data_type : Int) : Bool;
+	function closeCursor() : Bool;
+	function columnCount() : Int;
+	function debugDumpParams() : Bool;
+	function errorCode() : String;
+	function errorInfo() : NativeArray;
+	function execute(input_parameters : NativeArray) : Bool;
+	function fetch(?fetch_style : Int = 4, ?cursor_orientation : Int = 0, ?cursor_offset : Int = 0) : Dynamic;
+	function fetchAll(?fetch_style : Int, ?fetch_argument:Dynamic, ?ctor_args:NativeArray) : NativeArray;
+	function fetchColumn(?column_number : Int = 0) : String;
+	function fetchObject(?class_name : String, ?ctor_args : NativeArray) : Dynamic;
+	function getAttribute(attribute : Int) : Dynamic;
+	function getColumnMeta(column : Int) : NativeArray;
+	function nextRowset() : Bool;
+	function rowCount() : Int;
+	function setAttribute(attribute : Int, value : Dynamic) : Bool;
+	function setFetchMode(mode : Int, ?fetch : Dynamic, ?ctorargs : NativeArray) : Bool;
+}

+ 28 - 0
std/php7/db/SQLite3.hx

@@ -0,0 +1,28 @@
+package php.db;
+
+import haxe.Constraints;
+import php.*;
+import haxe.extern.EitherType;
+
+@:native('SQLite3')
+extern class SQLite3 {
+	static function version() : NativeArray;
+	static function escapeString(value:String) : String;
+	function busyTimeout(msecs:Int) : Bool;
+	function changes() : Int;
+	function close() : Bool;
+	function new(filename:String, ?flags:Int, encryption_key:String = null) : Void;
+	function createAggregate(name:String, step_callback:Function, final_callback:Function, argument_count:Int = -1) : Bool;
+	function createCollation(name:String, callback:Function) : Bool;
+	function createFunction(name:String, callback:Function, argument_count:Int = -1) : Bool;
+	function enableExceptions( enableExceptions:Bool = false) : Bool;
+	function exec(query:String) : Bool;
+	function lastErrorCode() : Int;
+	function lastErrorMsg() : String;
+	function lastInsertRowID() : Int;
+	function loadExtension(shared_library:String) : Bool;
+	function open(filename:String, ?flags:Int, encryption_key:String = null) : Void;
+	function prepare(query:String) : SQLite3Stmt;
+	function query(query:String) : EitherType<Bool,SQLite3Result>;
+	function querySingle(query:String, entire_row:Bool = false) : Dynamic;
+}

+ 14 - 0
std/php7/db/SQLite3Result.hx

@@ -0,0 +1,14 @@
+package php.db;
+
+import php.*;
+import haxe.extern.EitherType;
+
+@:native('SQLite3Result')
+extern class SQLite3Result {
+	function columnName(column_number:Int) : String;
+	function columnType(column_number:Int) : Int;
+	function fetchArray(?mode:Int) : EitherType<Bool,NativeAssocArray<String>>;
+	function finalize() : Bool;
+	function numColumns() : Int;
+	function reset() : Bool;
+}

+ 16 - 0
std/php7/db/SQLite3Stmt.hx

@@ -0,0 +1,16 @@
+package php.db;
+
+import php.*;
+import haxe.extern.EitherType;
+
+@:native('SQLite3Stmt')
+extern class SQLite3Stmt {
+	function bindParam(sql_param:EitherType<String,Int>, param:Ref<Dynamic>, ?type:Int) : Bool;
+	function bindValue(sql_param:EitherType<String,Int>, value:Dynamic, ?type:Int) : Bool;
+	function clear() : Bool;
+	function close() : Bool;
+	function execute() : SQLite3Result;
+	function paramCount() : Int;
+	function readOnly() : Bool;
+	function reset() : Bool;
+}

+ 31 - 0
std/php7/net/SslSocket.hx

@@ -0,0 +1,31 @@
+/*
+ * Copyright (C)2005-2016 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.net;
+
+class SslSocket extends sys.net.Socket {
+
+	public function new() : Void {
+		super();
+		protocol = "ssl";
+	}
+
+}

+ 64 - 0
std/php7/reflection/ReflectionClass.hx

@@ -0,0 +1,64 @@
+package php.reflection;
+
+import haxe.extern.Rest;
+
+@:native('ReflectionClass')
+extern class ReflectionClass implements Reflector {
+    @:phpClassConst static var IS_IMPLICIT_ABSTRACT : Int;
+    @:phpClassConst static var IS_EXPLICIT_ABSTRACT : Int;
+    @:phpClassConst static var IS_FINAL : Int;
+
+    static function export( argument:Dynamic, returnValue:Bool = false ) : String;
+
+    var name : String;
+
+    function new( argument:Dynamic ) : Void;
+    function getConstant( name:String ) : Dynamic;
+    function getConstants() : NativeAssocArray<Dynamic>;
+    function getConstructor() : ReflectionMethod;
+    function getDefaultProperties() : NativeAssocArray<Dynamic>;
+    function getDocComment() : String;
+    function getEndLine() : Int;
+    // function getExtension() : ReflectionExtension;
+    function getExtensionName() : String;
+    function getFileName() : String;
+    function getInterfaceNames() : NativeIndexedArray<String>;
+    function getInterfaces() : NativeIndexedArray<ReflectionClass>;
+    function getMethod( name:String ) : ReflectionMethod;
+    function getMethods( ?filter:Int ) : NativeIndexedArray<ReflectionMethod>;
+    function getModifiers() : Int;
+    function getName() : String;
+    function getNamespaceName() : String;
+    function getParentClass() : Null<ReflectionClass>;
+    function getProperties( ?filter:Int ) : NativeIndexedArray<ReflectionProperty>;
+    function getProperty( name:String ) : ReflectionProperty;
+    function getShortName() : String;
+    function getStartLine() : Int;
+    function getStaticProperties() : NativeAssocArray<Dynamic>;
+    function getStaticPropertyValue( name:String, ?def_value:Ref<Dynamic> ) : Dynamic;
+    function getTraitAliases() : NativeAssocArray<String>;
+    function getTraitNames() : NativeIndexedArray<String>;
+    function getTraits() : NativeIndexedArray<ReflectionClass>;
+    function hasConstant( name:String ) : Bool;
+    function hasMethod( name:String ) : Bool;
+    function hasProperty( name:String ) : Bool;
+    function implementsInterface( interfaceName:String ) : Bool;
+    function inNamespace() : Bool;
+    function isAbstract() : Bool;
+    function isAnonymous() : Bool;
+    function isCloneable() : Bool;
+    function isFinal() : Bool;
+    function isInstance( object:{} ) : Bool;
+    function isInstantiable() : Bool;
+    function isInterface() : Bool;
+    function isInternal() : Bool;
+    function isIterateable() : Bool;
+    function isSubclassOf( className:String ) : Bool;
+    function isTrait() : Bool;
+    function isUserDefined() : Bool;
+    function newInstance( args:Rest<Dynamic> ) : Dynamic;
+    function newInstanceArgs( ?args:NativeIndexedArray<Dynamic> ) : Dynamic;
+    function newInstanceWithoutConstructor() : Dynamic;
+    function setStaticPropertyValue( name:String , value:String ) : Void;
+    @:phpMagic function __toString() : String;
+}

+ 35 - 0
std/php7/reflection/ReflectionFunctionAbstract.hx

@@ -0,0 +1,35 @@
+package php.reflection;
+
+
+@:native('ReflectionFunctionAbstract')
+extern class ReflectionFunctionAbstract implements Reflector {
+
+    var name : String;
+
+    function getClosureScopeClass() : ReflectionClass;
+    function getClosureThis() : Dynamic;
+    function getDocComment() : String;
+    function getEndLine() : Int;
+    // function getExtension() : ReflectionExtension;
+    function getExtensionName() : String;
+    function getFileName() : String;
+    function getName() : String;
+    function getNamespaceName() : String;
+    function getNumberOfParameters() : Int;
+    function getNumberOfRequiredParameters() : Int;
+    // function getParameters() : NativeIndexedArray<ReflectionParameter>;
+    // function getReturnType() : ReflectionType;
+    function getShortName() : String;
+    function getStartLine() : Int;
+    function getStaticVariables() : NativeAssocArray<Dynamic>;
+    function hasReturnType() : Bool;
+    function inNamespace() : Bool;
+    function isClosure() : Bool;
+    function isDeprecated() : Bool;
+    function isGenerator() : Bool;
+    function isInternal() : Bool;
+    function isUserDefined() : Bool;
+    function isVariadic() : Bool;
+    function returnsReference() : Bool;
+    @:phpMagic function __toString() : String;
+}

+ 35 - 0
std/php7/reflection/ReflectionMethod.hx

@@ -0,0 +1,35 @@
+package php.reflection;
+
+import haxe.Constraints;
+import haxe.extern.Rest;
+
+@:native('ReflectionMethod')
+extern class ReflectionMethod extends ReflectionFunctionAbstract {
+    @:phpClassConst static var IS_STATIC : Int;
+    @:phpClassConst static var IS_PUBLIC : Int;
+    @:phpClassConst static var IS_PROTECTED : Int;
+    @:phpClassConst static var IS_PRIVATE : Int;
+    @:phpClassConst static var IS_ABSTRACT : Int;
+    @:phpClassConst static var IS_FINAL : Int;
+
+    // public var class : String;
+
+    public static function export( className:String, name:String, ?returnValue:Bool) : String;
+
+    public function new( cls:Dynamic, name:String ) : Void;
+    public function getClosure( object:{} ) : Function;
+    public function getDeclaringClass() : ReflectionClass;
+    public function getModifiers() : Int;
+    public function getPrototype() : ReflectionMethod;
+    public function invoke( object:{}, args:Rest<Dynamic> ) : Dynamic;
+    public function invokeArgs( object:{}, args:NativeIndexedArray<Dynamic> ) : Dynamic;
+    public function isAbstract() : Bool;
+    public function isConstructor() : Bool;
+    public function isDestructor() : Bool;
+    public function isFinal() : Bool;
+    public function isPrivate() : Bool;
+    public function isProtected() : Bool;
+    public function isPublic() : Bool;
+    public function isStatic() : Bool;
+    public function setAccessible( accessible:Bool ) : Void;
+}

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä