# php2go Convert PHP source code to Go by AST walking. The goal is to produce idiomatic, maintainable Go code as part of a one-off conversion. This is not generally possible for highly dynamic PHP code, that may require manual fixups. ## Progress ### Phase 1 - [X] Convert some small programs - [X] Error handling - [X] All functions return `(type, error)` - [X] Convert `throw` to err return - [X] Non-leaf function calls need to check + bubble errors - [X] Array handling - [X] Infer whether to use slice/map for PHP array - [-] Namespaces - [X] Basic support for `namespace` -> package name transformation - [ ] Resolve namespace names in calls - [ ] Resolve `use` statements - [X] `if` - [X] `for`/`foreach` - [X] `switch` - [ ] Generators - [ ] Goto - [X] `null` -> `nil` - [X] Consts and `define()` - [X] Magic constants (`__LINE__`,`__FILE__` etc) - [ ] Predefined constants (`PHP_VERSION`, `PHP_EOL`, `PHP_OS`, `PHP_INT_MAX` etc) - [ ] `isset`/`unset` - [ ] `instanceof` - [X] Ternary expressions - Implemented as inline closure - [X] `die` - [X] `try`/`catch`/`finally` - [X] Implement using err checks, not panic/recover - Any statements within the try block should capture the finally/catch to run within any interior err-check blocks - [ ] `finally` - Runs before any return statement inside the try block or catch block; also runs after the try block is complete - Maybe `finally` would be more concisely implemented as defer inside an IIFE, but that is not idiomatic, maintainable Go code - [X] Abandon upon sight of highly dynamic constructs - [X] `eval` - [X] `extract` - [ ] variable-variables - [ ] Attempts to enable magic_quotes or register_globals - [X] Detect assignment expressions - Go doesn't support assignment in rvalues, only as a statement - When walking below stmt level, need to first fully walk and check for any function calls + assignments that may need hoisting (and we can probably only do that correctly if there is no short-circuiting) - [X] Add subtree walk + catch error for this case - [X] Closures - [ ] Handle value/reference captures - [X] Convert top-level calls to `init()`/`main()` - [X] Wrap in function - [X] Determine init/main based on package name - [ ] Class/object transformations - [X] Convert `new X` constructor calls to `NewX` - [X] Visibility - [X] Apply PHP visibility modifiers as Go case change - [ ] Call mangled function name at call sites - *PHP variable names are case-sensitive, function names are case-insensitive* - [X] Static methods - [X] Inheritance *partial* - [X] Interfaces - [X] Class constants - [X] super - [X] Need to track current conversion state through into function generator, to select the concrete parent - [X] parent:: - [X] self:: - [ ] static:: - [ ] Traits / `use` - [ ] Abstract methods - [X] Track golang package imports - [X] Variadic function parameters - [X] Preserve comments ### Productionize - [ ] Multi-file programs - [ ] Include/Require - [ ] Infer whether to declare variable (`var` / `:=`) or reuse (`=`) - [ ] Track current visibility scope - [ ] Comprehensive coverage of all AST node types - [X] Create full-coverage interface to implement - [ ] Node - [ ] Stmt - [ ] Expr - [ ] Assign - [X] Binary - [X] Scalar - [X] Heredocs/nowdocs - [ ] Numbered break/continue - [ ] Type inference - [ ] Type declarations for literals (string, slice/map with constant initializer, etc) - [ ] Convert known PHP typenames to Go equivalents - [ ] Parse extra types from phpdoc blocks - [X] Hoisting pass for rvalue expressions - [X] Preincrement statements - [ ] Behaviour of function calls in rvalue cases where err cannot be checked - [ ] Assignment expressions - [ ] Alternately - we can support the form `if foo := bar(); foo {` - [ ] Simple standard library transformations - [X] common string/array functions - [ ] More string/array functions - [ ] Top 100 from https://www.exakat.io/top-100-php-functions/ - [X] substr -> slice index operator - This has the same value semantics for ~~string literals, but not variables~~ all cases - [ ] error_reporting(E_ALL) --> just remove it - [ ] ini_set('display_errors', 'On') --> remove it when the parameter is known - [ ] Elide error return for functions that cannot throw - ?? Could be a standalone Go refactoring tool ### Moonshots - [ ] Extended library/environment transformations - [ ] Standard library transformations - [X] Track golang package imports - [ ] Handle conflicts between golang stdlib packages / local variable names - [ ] uasort -> sort.Slice - [ ] preg -> regexp - [ ] json -> encoding/json - [ ] Output buffering (`ob_start` / `ob_get_clean`) - Can push/pop os.Stdout onto a private stack, then we can keep using `fmt.Print` - [ ] PHP Superglobal transformations - [ ] `$_SERVER['argv']` to os.Args - [ ] `$_GET['name']` to r.FormValue('name') - [ ] Common 3rd party package transformations to popular equivalents (optional) - [ ] Guzzle - [ ] AWS SDK - [ ] PHPUnit -> Go Test - [ ] Replace Composer/PSR-4 autoloading with Go imports - [ ] Preserve rough line spacing - [ ] Somehow detect whether map use should be order-preserving - [ ] Support scoped namespace (`namespace { ... }`) and multiple namespaces in file - [ ] Validation on imported comment formats - [ ] Convert wordpress / mediawiki / symfony - [ ] Option to convert with preset=cli, preset=web, webroot path - [ ] Option to generate built-in web server - [ ] Generate source maps - The parser does have full positional information - exporting at the stmt level would be reasonable - But the gofmt pass may lose this information - [ ] Command-line tool option to `go run` ## Reference - [The Go Programming Language Specification](https://golang.org/ref/spec)