Pratphall - A typed language targeting PHP*

*Actually, it's just TypeScript cross-compiled.

Doc | Try | GitHub | Mailing List
 

Features

  • Optional typing
  • Readable PHP output
  • IDE support
  • Metaprogramming facilities
  • PHP interoperability
  • MIT licensed

Anti-Features

  • Not fixing PHP standard library
  • Not emitting obtuse/complicated PHP code
  • Not auto-generating Pratphall from PHP code
  • Not adding any code in TypeScript core
  • Not supporting every PHP feature
  • Not supporting every JS/TypeScript feature

Overview

Pratphall is an optionally-typed language that compiles to readable PHP. PHP has a powerful engine and is very scalable since state is primarily per-request for PHP scripts. Unfortunately, due to the dynamic nature of PHP, it can be difficult to build large projects and retain the ability to refactor and manage the code. It can also be difficult to foresee errors with typing and unavailable variables. Almost all of these issues cause many problems that don't surface until runtime. Pratphall aims to solve this.

Pratphall started as kind of a joke (hence the name) and proof of concept to see if TypeScript could be reliably translated. It turns out it can. So Pratphall is for all practical purposes just TypeScript (which is a typed superset of JavaScript) cross-compiled. And although not every single JS idiom directly translates, remembering that Pratphall is just TypeScript which is just typed JavaScript will help development greatly.

Example

Here is an example of Pratphall compiling to PHP
//normal array
var arr = [1, 2, 3, 4, 5];

//loop and print
arr.forEach((value: number) => {
    echo('My value: ' + value + '\n');
});

//compile-time-only class
interface SampleContract extends Pct.CompileTimeOnly {
    requiredProperty: string;
    optionalProperty?: bool;
}

//function using compile-time class
function printInfo(info: SampleContract) {
    echo('Required: ' + info.requiredProperty + '\n');
    if (typeof info.optionalProperty !== 'undefined') {
        echo('Optional: ' + info.optionalProperty + '\n');
    }
}

//type inferred matching
printInfo({ requiredProperty: 'required val' });
//normal array
$arr = [1, 2, 3, 4, 5];

//loop and print
foreach ($arr as $value) {
    echo('My value: ' . $value . "\n");
}



/*Spacing added in example for clarity*/



//function using compile-time class
function printInfo($info) {
    echo('Required: ' . $info->requiredProperty . "\n");
    if (array_key_exists('optionalProperty', $info)) {
        echo('Optional: ' . $info->optionalProperty . "\n");
    }
}

//type-inferred matching
printInfo((object)[ 'requiredProperty' => 'required val' ]);

To use Pratphall from the command line, simply install via NPM (it's a little large since it includes source for metaprogramming facilities):

npm install -g pratphall

You may also want to install TypeScript for Visual Studio 2012 if you want to use Visual Studio as your editor. For more information about Visual Studio support, see below. If using Pratphall in an editor, you may not want to use the -g option which installs globally; this way you can directly reference node_modules/pratphall/bin/php.d.ts in your source.

If you want to build Pratphall from source, see the Building From Source appendix.

Write the following simple script and save it as sayHello.ts:

function sayHello(subject: string) {
    return 'Hello, ' + subject;
}

var theSubject = 'World';

echo(sayHello(theSubject) + '\n');

Now, to compile to PHP, run ppc like so:

ppc sayHello.ts

This will create a sayHello.php file that looks like this:

function sayHello($subject) {
    return 'Hello, ' . $subject;
}

$theSubject = 'World';

echo(sayHello(theSubject) . "\n");

Running this with PHP will output what you expect. However, if you tried to compile this:

function sayHello(subject: string) {
    return 'Hello, ' + subject;
}

var theSubject = 123;

echo(sayHello(theSubject) + '\n');

You would get: sayHello.ts(7,5): Supplied parameters do not match any signature of call target. This is because you are attempting to pass a number to a function that only accepts strings.

Who?

Nobody really. It's a project that was started in my spare time and only maintained in my spare time. There is no commercial support, no guarantee that anything will get fixed, and no guarantee that the project will be properly maintained. The only project known to use Pratphall is dust-php. If Pratphall becomes popular, it is possible it could become a more professional language. Feel free to discuss the language or ask questions on the mailing list.

What?

Pratphall is TypeScript compiled to PHP. It includes several helpers to make this easier. Pratphall's code is licensed under the MIT license, but the Microsoft TypeScript code within (referenced as a submodule) is licensed under the Apache 2 license.

Where?

The source is on GitHub and the site is on GitHub. Follow development, fork, send pull requests, and submit issues there.

When?

I don't know. It's in an almost alpha state until it gets more traction.

Why?

This is basically for static typing enthusiasts that use PHP either because they are forced to or like the PHP engine and scalability. Using PHPDoc annotations is rarely a good enough solution and editor support for them is limited. After noticing extreme parity between TypeScript and PHP, a simple tool was built to do the cross-compiling. This is the result.

Pratphall can be used to make a really scalable codebase in PHP. It can also reduce verbosity (e.g. several classes/modules in one file) and increase productivity through editor support (e.g. Visual Studio with IntelliSense). Refactoring and determining use throughout the your codebase will now be really easy. And, if the abstraction is written properly, code can even be shared between JS/PHP. At the very least this really helps when defining typed model classes.

How?

Pratphall simply leverages the TypeScript compiler and type checker. Because TypeScript is written so well, it is very easy to change the language it emits to. In this case, a new emitter was written to just write PHP instead of JavaScript.

ppc [options] FILE...

Options:

-c, --config FILE
Use a JSON file for configuration options. Note values in the config file override command line options before this option and are overridden by command line options after this option. Read about Configuration files below.
--exclude-outside
Do not emit Pratphall files referenced in directories above and outside the given file. This is helpful for when you may only want to emit code from a test directory, not all the other code it references.
--ext FILE
Can be used as many times as necessary to include extensions (see metaprogramming below)
--force-block
Forces if, else, while, etc to have blocks on output even if single statements are given on input
--function-brace-newline
Put the opening brace of functions (but not closures) on the next line
-h, --help
Display help
--indent-spaces COUNT
Indent using the number of given spaces. The default is 4 spaces.
--indent-tabs
Indent using a single tab. The default is 4 spaces.
--lint
Do not output files, just parse/compile
--no-comments
Do not emit comments
--no-js-lib
Do not automatically include the lib.d.ts JS definitions
--no-organize
When set, this will not organize source files into the PSR-0 autoloader-acceptable filesystem structure
--no-php-lib
Exclude the php.d.ts PHP definitions
--no-type-hint
Do not type hint emitted functions in any way
-o, --out PATH
When --single is present or there is only a single file on the command line, this is the single file to output to. References in the file are emitted relative to this single file path when not using --single. Otherwise, this is the directory to put all files at relative to the files given.
--prefer-single-quotes
When set, this will try to use single quotes for all strings that don't have escape characters
--require-references
When set, all ///<reference /> will become require_once. This is only allowed when --no-organize is set.
--single
Compile all files to a single PHP file. This is basically also setting --no-organize also, so both cannot be present.
--type-brace-newline
Put the opening brace of classes and interfaces on the next line
--use-else-if
When an "else if" is encountered in Pratphall, translate to "else if" instead of the default "elseif"
--verbose
Log extra information on compile
-w, --watch
Re-compile all files on any file changes (including referenced files). Note, if not using --single this means files and directories created during compilation may be deleted on later compilation. Files are not overwritten if their output contents didn't change. Finally note this does not always work over remotely mounted filesystems.
--watch-debounce-ms MS
The number of milliseconds to wait for file change events to stop before re-compilation. The default is 1500 (1.5 seconds).

Booleans and conversions happen the same way in Pratphall as they do in PHP.

Strings in Pratphall and PHP are somewhat similar. There are no multiline strings. There is no string interpolation (attempts are escaped). Usually, the preference of single quote or double quote in the Pratphall script is translated verbatim to PHP. However, if there is an escape character in a single-quoted string, it will become double quoted. To request that all strings without escape characters to become single quoted in PHP, use the --prefer-single-quotes compiler option.

In Pratphall strings are concatenated with a plus sign. In PHP the dot operator is used. Type inference is used to determine when this translation should occur. In Pratphall, if either side of the plus operator is a string, concatenation is assumed. If either side of a plus operator is an unknown/any type a normal arithmetic plus will be used and a compiler warning will be issued.

Normal JavaScript string functions are translated to common PHP idioms with some gotchas.

//will be converted to double quotes
var a = 'My\nNewline\nString$escaped{$interpolation}';

//concatenation
var b = 99 + ' bottles of beer on the wall';

//compiler warning because type is any
var c: any = 'test string';
var d = 12 + c;

//common JS functions
var_dump(b.length);
var_dump(b.charAt(0));
var_dump(b.split(' '));
//will be converted to double quotes
$a = "My\nNewline\nString\$escaped{\$interpolation}";

//concatenation
$b = 99 . ' bottles of beer on the wall';

//compiler warning because type is any
$c = 'test string';
$d = 12 + $c;

//common JS functions
var_dump(strlen($b));
var_dump($b[0]);
var_dump(explode(' ', $b));

In JS there is no difference between an integer and a float for the most part, and the same is true in Pratphall. Conversion and testing can still occur at runtime with intval, floatval, and other methods. At compile time however, they are simply numbers. There is no normal way to constrain a variable on one type or the other. Hexadecimal and octal literals are translated to normal decimal integers during translation.

Unlike PHP, Pratphall differentiates between associative arrays and normal indexed arrays. The former is of type Pct.PhpAssocArray whereas the latter is a normal JS array. This can be confusing at first, but in practice it helps the developer make more accurate assumptions about the typing of variables. You can convert between these types at compile time using Pct.toAssocArray or Pct.toArray. Note when using the latter, (until TypeScript has generics) the result is any[] so it is recommended to cast it to the exact form of array expected.

Associative arrays can be created with Pct.newAssocArray. Only object literals can be passed to the function. Indexed arrays are handled almost exactly like they are in JS. They are created with the normal bracketed syntax.

Normal JavaScript array functions are translated to common PHP idioms with a few gotchas.

//regular array
var a = [1, 2, 3];

//some calls
a.forEach((value: number) => {
    var_dump(value);
});
a.push(4);

//associative array
var b = Pct.newAssocArray({
    prop: 'propValue',
    prop2: ['a', 'b', 'c'],
    closure: function () { echo('Hey!\n'); }
});

//some calls
var c = b.map((value: any) => {
    return gettype(value);
});
c['prop3'] = 15;
var_dump(c.length);
//regular array
$a = [1, 2, 3];

//some calls
foreach ($a as $value) {
    var_dump($value);
}
$a[] = 4;

//associative array
$b = [
    'prop' => 'propValue',
    'prop2' => ['a', 'b', 'c'],
    'closure' => function () { echo("Hey!\n"); }
];

//some calls
$c = array_map(function ($value) {
    return gettype($value);
}, $b);
$c['prop3'] = 15;
var_dump(count($c));

Objects in Pratphall and PHP work very similarly. Anonymous object literals become an stdClass via cast. Note, if you have a closure as an object property, it cannot necessarily be invoked like a method in PHP, so Pratphall has to do special handling (see GOTCHA-001). TypeScript property accessors are not currently supported.

var obj = {
    num: 12,
    arr: ['a', 'b', 'c'],
    obj: { innerNum: 12 },
    func: (value: string) => { echo('Value: ' + value); }
};
$obj = (object)[
    'num' => 12,
    'arr' => ['a', 'b', 'c'],
    'obj' => (object)[ 'innerNum' => 12 ],
    'func' => function ($value) { echo('Value: ' . $value); }
];

PHP resources are represented by the Pct.PhpResource type in Pratphall.

Null is handled the same way in Pratphall and PHP.

Undefined is different. In Pratphall, delete translates directly to unset. Conditions that check typeof undefined are translated to safe PHP that avoids false positives with NULL values unlike isset.

Functions isset and empty are used like any other PHP function in Pratphall. Since these are language constructs, the values don't necessarily have to exist like they do in JS.

//normal null
var a = { prop1: null };
echo('a.prop1 null? ' + (a.prop1 == null));

//undefined
delete a.prop1;
echo('a.prop1 set? ' + (typeof a.prop1 == 'undefined'));
//normal null
$a = (object)[ 'prop1' => null ];
echo('a.prop1 null? ' . ($a->prop1 == null));

//undefined
unset($a->prop1);
echo('a.prop1 set? ' . (!array_key_exists('prop1', $a)));

Pratphall supports full typed closure type definitions instead of just the callable type hint in PHP. Even methods of objects can be passed around like normal.

class Foo {
    bar(value: string) { echo('Value: ' + value); }
}

var foo = new Foo();
var f = foo.bar;
//call
f('test');
class Foo {
    public function bar($value) { echo('Value: ' . $value); }
}

$foo = new Foo();
$f = (new \ReflectionMethod('Foo', 'bar'))->getClosure($foo);
//call
$f('test');

This is safe since unlike PHP, Pratphall does not support naming properties/variables and methods/functions the same name. See GOTCHA-002 about interoperating with existing PHP that does.

Void can be used for return types of functions. There is no such thing as mixed, but there is any which loosely translates. The use of the any type should be avoided when possible. If using any, you are encouraged to cast to a known type as soon as you can.

To cast to a value at compile time, use the TypeScript method. For example: <bool><any>stringValue casts a string to a bool but will not be casted in the emitted PHP code. This is helpful for functions that return a value or FALSE. In fact, this is such a common pattern that there are compile-time helpers for it: Pct.isFalse and Pct.isNotFalse.

To cast a value at runtime, it is always preferred to use the built-in PHP methods such as `strval`, `intval`, etc. If you must have a literal cast, you can use the `Pct.cast*` functions.

function printNumber(value: number) {
    echo('Number: ' + value + '\n');
}

//compile-time cast only
printNumber(<number><any>'10');

//runtime PHP function cast
printNumber(intval('10'));

//runtime PHP explicit cast
printNumber(Pct.castInt('10'));

//two ways to check a FALSE return
if (<bool><any>strpos('team', 'I') === false) {
    echo('There is no "I" in "team"\n');
}
if (Pct.isFalse(strpos('team', 'I'))) {
    echo('There is no "I" in "team"\n');
}
function printNumber($value) {
    echo('Number: ' . $value . "\n");
}

//compile-time cast only
printNumber('10');

//runtime PHP function cast
printNumber(intval('10'));

//runtime PHP explicit cast
printNumber(((int) '10'));

//two ways to check a FALSE return
if (strpos('team', 'I') === false) {
    echo("There is no \"I\" in \"team\"\n");
}
if (strpos('team', 'I') === false) {
    echo("There is no \"I\" in \"team\"\n");
}

Variables names are case sensitive and are NOT prefixed with dollar signs (except for references, see later).

All variables in Pratphall are defined somewhere. If they are declared globally and are used in a function, the global keyword is applied in the translated PHP. There is no Pratphall equivalent to the static variable in PHP (not to be confused with the static property/function of a class).

var a = 'myGlobalString';

function printGlobalString() {
    /*blank space here for clarity*/
    echo('Global string: ' + a);
}
$a = 'myGlobalString';

function printGlobalString() {
    global $a;
    echo('Global string: ' + $a);
}

"Variable variables" are not supported in Pratphall in any way. The best you can do is access an object's property by its string-based name using the bracket syntax.

var obj = { child: { grandchild: 5 }};
echo('Grandchild val: ' + obj.child['grand' + 'child']);
$obj = (object)[ 'child' => (object)[ 'grandchild' => 5 ]];
echo('Grandchild val: ' . $obj->child->{'grand' . 'child'});

By default in Pratphall, variable names that are completely capitalized are assumed to be constant and variables that are not are assumed to be normally named. To override this behavior, use Pct.const or Pct.asVar when referencing the variable to change Pratphall's default. Note, the superglobals GLOBALS, _SERVER, _GET, _POST, _FILES, _COOKIE, _SESSION, _REQUEST, and _ENV are all automatically known by Pratphall to be prefixed with dollar signs.

All operators work the same in Pratphall and PHP with the following exceptions:

clone
The Pratphall language has no keyword for clone. You can get the same effect by using Pct.clone
var obj = { foo: 'bar' };
var copy = Pct.clone(obj);
$obj = (object)[ 'foo' => 'bar' ];
$copy = clone $obj;
.
String concatenation is done via + and translated based on type inference. Same goes for .= in PHP which is += in Pratphall.
and, xor, or
Completely unsupported in Pratphall (not to be confused with support for && and ||).
>>>
PHP does not have a zero-fill right shift, so the presence of this operator in Pratphall will cause a compiler error
?:
Pratphall supports the normal PHP ternary, but does not support the shorthand form which uses the conditional as the first result.
&
Reference types and reference assignment are handled differently in Pratphall. See the References section.
<>
This is considered "not equal" in PHP. Pratphall does not support it.
@
The @ symbol may not be used to swallow errors in Pratphall. If you must swallow errors, use Pct.swallowErrors (unwieldy name on purpose) which will use the @ sign.
var f = Pct.swallowErrors(file('not-here.txt'));
$f = @file('not-here.txt');
`
Backticks are unsupported in Pratphall. Use shell_exec if you must.
+
Addition with numbers works normally. Unioning arrays, if you must, is done with Pct.unionArray. Note, this comes back with any[] if you are using an indexed array, so please cast immediately back to what you expect it to be.
var a = <number[]>Pct.unionArray([1, 2, 3], [4, 5, 6, 7]);
$a = [1, 2, 3] + [4, 5, 6, 7];
==, !=, ===
These translate directly, but it's important to understand that TypeScript/JS and PHP don't treat array or object equality the same, so be careful when writing shareable code comparing arrays or objects.
instanceof
This check will work just fine in Pratphall when the right hand side is the literal name of a type. If the right hand side is a string or some other expression you must use Pct.isInstance. Of course, is_a may be also be used as part of the PHP standard library.
class Foo { }
var a = new Foo();
var b = Pct.isInstance(a, 'Foo');
class Foo { }
$a = new Foo();
$b = a instanceof 'Foo';
typeof
This has no operator/construct equivalent in PHP, but it is automatically translated to gettype (except for as used for checks with undefined). Note, the results can differ between JS and PHP, so make sure you code to the PHP environment or abstract when writing shareable code.

All control structures work the same in Pratphall and PHP with the following exceptions:

elseif
Use else if in Pratphall which will translate to elseif in PHP by default. The --use-else-if compiler option can be used to emit else if instead.
if():, elseif:, else:, endif;, while:, endwhile;, for:, endfor;, foreach:, endforeach;, switch:, endswitch;
Unsupported in Pratphall
for...in
This JS concept isn't present in any way in PHP and isn't worth the significant runtime code to support accurately. If this is seen, a compiler warning is issued and it's translated to a foreach of array_keys of an array cast which is not the exact same thing. These loops are discouraged.
var a = { b: 1, c: 2 };
for (b in a) {
    echo('a[' + b + ']: ' + a[b] + '\n');
}
$a = (object)[ 'b' => 1, 'c' => 2 ];
foreach (array_keys($a) as $b) {
    echo('a[' . $b . ']: ' . $a->{$b} . "\n");
}
foreach
This is represented in Pratphall by the forEach function that can be called on an iterable object or an array. If the function passed to forEach is an inline closure, it will be translated directly. Otherwise, it will be translated to an array_walk call.
var a = Pct.newAssocArray({ b: 1, c: 2 });

//regular
a.forEach((value: number, index: string) => {
    echo('a[' + index + ']: ' + value + '\n');
});

//callback
var d = (value: number, index: string) => {
    echo('a[' + index + ']: ' + value + '\n');
};
a.forEach(d);
$a = (object)[ 'b' => 1, 'c' => 2 ];

//regular
foreach ($a as $index => $value) {
    echo('a[' + $index + ']: ' + $value + "\n");
}

//callback
$d = function ($value, $index) {
    echo('a[' + $index + ']: ' + $value + "\n");
};
array_walk($a, $d);
break #, continue #
In Pratphall, break and continue statements are optionally associated with labels instead of a number. Normal breaks and continues in Pratphall work as normal. When a label is defined though, the construct becomes a goto. There is no equivalent for PHP's numbered break and continue statements. For example, `outside: while (a) { while (b) { break outside; } }` translates to `outside: while ($a) { while ($b) { goto outside; } }`.
var counter = 0;
again:
var lines = file('file' + (++counter) + '.txt');
for (var i = 0; i < lines.length; i++) {
  var words = lines[i].split(' ');
  for (var j = 0; j < words.length; j++) {
      var word = words[j];
      if (word == 'end') break done;
      else if (word == 'nextfile') break again;
      else echo('Word: ' + word + '\n');
  }
}
done:
echo('Done!\n');
$counter = 0;
again:
$lines = file('file' + (++$counter) + '.txt');
for ($i = 0; $i < count($lines); $i++) {
  $words = explode(' ', lines[$i]);
  for ($j = 0; $j < count($words); $j++) {
      $word = $words[$j];
      if ($word == 'end') goto done;
      elseif ($word == 'nextfile') goto again;
      else echo('Word: ' . $word . "\n");
  }
}
done:
echo("Done!\n");
declare
Not a construct in Pratphall, but can be called using Pct.declare. If a function is the last parameter of the call, it considers code within to be in a declare block.
return
Return from methods/functions works normally. Global return statements are unsupported
include, include_once, require, require_once
These are normal functions, but do not affect type checking. In order to affect type-checking, you must use ///<reference /> elements at the top of your file. If the --require-references compiler option is set, reference elements will become require_once calls.
goto
Unsupported in Pratphall

Pratphall recommends avoiding references. If you cannot, they are supported.

To assign by reference or otherwise reference, use Pct.byRef.

To pass by reference, the parameter in the function must start with a dollar sign. A compiler error occurs if the item passed by reference is not valid (e.g. expressions or literals).

To return by reference, the function name must start with a dollar sign. Also, to receive the returned result as a reference, you must call Pct.byRef.

//assign
var a = 'hey';
var b = Pct.byRef(a);
//pass
function addWord($val: string) {
    $val += ' word';
}
addWord(b);
echo('Changed? ' + (a == 'hey word'));
//return
var c = { d: 15 };
function $getReference(val: { d: number; }) {
    return val.d;
}
var e = Pct.byRef($getReference(c));
e = 20;
echo('Changed? ' + (c.d == 20));
//assign
$a = 'hey';
$b = &$a;
//pass
function addWord(&$val) {
    $val .= ' word';
}
addWord($b);
echo('Changed? ' . ($a == 'hey word'));
//return
$c = (object)['d' => 15];
function &getReference($val) {
    return $val->d;
}
$e = &getReference($c);
$e = 20;
echo('Changed? ' . ($c->d == 20));

Functions in Pratphall behave very similarly to PHP.

Overloads declarations are allowed in Pratphall like they are in TypeScript, but only one "catch all" function with an implementation is allowed. The overloaded signatures will be discarded.

Type hinting is done by default for arrays, callables, and actual type declarations. Parameters who are typed with compile time only types (see compile time declarations below) will not be type hinted. If the compiler option --no-type-hint is set, type hinting will not be present on any function.

Pratphall directly supports typed variadic function arguments (known as "RestParameters" in the TypeScript specification) whereas PHP does not. The use of variadic functions is not encouraged, but supported.

When the arguments array is referenced in a function, it is translated to PHP by using func_get_args (see GOTCHA-003 about re-defining arguments). When a rest parameter is used as a parameter in a function, it is derived from func_get_args

function myprint(one: string, ...args: any[]) {
    /* left blank to make comparison easier */

    echo('First: ' + arguments[0] + '\n');
    echo('Last: ' + arguments[arguments.length - 1] + '\n');
    if (args.length > 0) {
        echo('First args: ' + args[0] + '\n');
        echo('Last args: ' + args[args.length - 1] + '\n');
    }
}

myprint('foo', true, 13.5, 'bar');
function myprint($one) {
    $arguments = func_get_args();
    $args = array_slice(func_get_args(), 1);
    echo('First: ' . $arguments[0] + "\n");
    echo('Last: ' . $arguments[count($arguments) - 1] . "\n");
    if (count($args) > 0) {
        echo('First args: ' . $args[0] . '\n');
        echo('Last args: ' . $args[count($args) - 1] . "\n");
    }
}

myprint('foo', true, 13.5, 'bar');

Both PHP and Pratphall support optional function parameters. PHP supports only default parameters with only scalars/arrays and they can be anywhere within the parameter list. Pratphall supports both optional and default parameters which can be initialized to any type and must be at the end of the parameter list.

Optional parameters in Pratphall without a default value are assumed to be null. If the default parameter is specified and it is not a constant, scalar value, it will be set at the beginning of the function (this practice is usually discouraged).

function words(prefix?: bool, file = file('default.txt')) {
    /* left blank to make comparison easier */
    file.forEach((line: string) => {
        line.split(' ').forEach((word: string) => {
            if (prefix) echo('Word: ');
            echo(word + '\n');
        });
    });
}

//reads default.txt and prints w/out prefix
words();
//uses array and prints w/ prefix
words(true, ['foo bar', 'fu bar']);
function words($prefix = null, $file = null) {
    if ($file === null) $file = file('default.txt');
    foreach ($file as $line) {
        foreach (explode(' ', $line) as $word) {
            if ($prefix) echo('Word: ');
            echo($word . "\n");
        }
    }
}

//reads default.txt and prints w/out prefix
printWords();
//uses array and prints w/ prefix
printWords(true, ['foo bar', 'fu bar']);

Anonymous and Nested Functions

Pratphall and PHP have support for anonymous functions with a common syntax and are invoked and passed the same way.

PHP's parser supports nested functions, but it places them in the global scope. Pratphall does NOT support these nested functions. When Pratphall encounters a nested function, it treats it like an anonymous function assigned to the variable of the same name. This means the compiler will error if a variable and nested function appear in the same function with the same name.

function func() {
    var anonFunc = (value: string) => { echo(value); }
    var anonFunc2 = function (value: string) { echo(value); }
    function nestedFunc(value: string) { echo(value); }
}
function func() {
    $anonFunc = function ($value) { echo($value); };
    $anonFunc2 = function ($value) { echo($value); };
    $nestedFunc = function ($value) { echo($value); };
}

Pratphall's (ahem, JS's) native try/catch syntax is much more limited than PHP's. It is supported and will even emit PHP 5.5 finally statements. You can compile-time cast the catch variable or do an instanceof check.

try {
    new ReflectionClass('NonExistentClass');
} catch (err) {
    if (err instanceof ReflectionException) {
        echo('Not found: ' + (<Exception>err).getMessage());
    } else {
        echo('Other: ' + (<Exception>err).getMessage());
    }
} finally {
    echo('This runs always in PHP 5.5');
}
try {
    new ReflectionClass('NonExistentClass');
} catch (Exception $err) {
    if ($err instanceof ReflectionException) {
        echo('Not found: ' . $err->getMessage());
    } else {
        echo('Other: ' . $err->getMessage());
    }
} finally {
    echo('This runs always in PHP 5.5');
}

Pratphall does include compile-time helpers to support the full try/catch syntax via Pct.try. It is an object literal w/ a try function, an optional catch function (or array of functions), and an optional finally function. If neither a catch nor finally is supplied, it assumes an empty catch statement.

Pct.try({
    try: () => {
        new ReflectionClass('NonExistentClass');
    },
    catch: [
        (err: ReflectionException) => {
            echo('Not found: ' + err.getMessage());
        },
        (err: Exception) => {
            echo('Other: ' + err.getMessage());
        }
    ],
    finally: () => {
        echo('This runs always in PHP 5.5');
    }
});
try {
    new ReflectionClass('NonExistentClass');
} catch (ReflectionException $err) {
    echo('Not found: ' . $err->getMessage());
} catch (Exception $err) {
    echo('Other: ' . $err->getMessage());
} finally {
    echo('This runs always in PHP 5.5');
}

Pratphall supports classes and interfaces just like PHP. There are several features that Pratphall does not support:

Despite these non-existent features, the Pratphall object-oriented system is very strong. Actually, in practice we've found the absence of some of these features leads to cleaner code. Here are some features that Pratphall does support:

//spacing added below for clarity
interface Iface {

    numberProperty: number;

    write(param: string);

    notRequired?(...params: any[]): bool;
}

class BaseClass {

    static fileContents = file_get_contents('myfile.txt');



    constructor(public numberProperty: number) {

        echo('Constructed!')
    }
}


class MyClass extends BaseClass implements Iface {

    static getFileContents() {
        return BaseClass.fileContents;
    }

    constructor() {
        super(12);
    }

    __destruct() { echo('Destructing!\n'); }

    private secretFunction() { echo('Hello\n'); }

    write(param: string) {
        echo('Value: ' + param + '\n');
    }

    __invoke(someVal: any) {
        echo('I have been invoked!\n');
        return this.numberProperty + Pct.castInt(someVal);
    }

    __get(prop: string) { return 42; }

    __set(prop: string, value: any) {
        echo('Setting ' + prop + ' with ' + value);
    }

    toString() { return 'MyClass'; }
}

var myClass = new MyClass();
echo('Instance? ' + (myClass instanceof Iface) + '\n');
//call static
var a = MyClass.getFileContents();
//call normal
myClass.write('Hey');
//invoke
var b = myClass.__invoke(20);
var c = myClass.__invoke('15');
//trigger getter/setter
var d = <number>(<any>myClass).someProp;
(<any>myClass).someNewProp = 20;
//string version
var e = myClass.toString();
//spacing added below for clarity
interface Iface {



    public function write($param);


}

class BaseClass {

    public static $fileContents;

    public $numberProperty;

    public function __construct($numberProperty) {
        $this->numberProperty = $numberProperty;
        echo('Constructed!');
    }
}
BaseClass::$fileContents = file_get_contents('myfile.txt');

class MyClass extends BaseClass implements Iface {

    public static function getFileContents() {
        return BaseClass::$fileContents;
    }

    public function __construct() {
        parent::__construct(12);
    }

    public function __destruct() { echo("Destructing!\n"); }

    private function secretFunction() { echo("Hello\n"); }

    public function write($param) {
        echo('Value: ' . $param . "\n");
    }

    public function __invoke($someVal) {
        echo("I have been invoked!\n");
        return $this->numberProperty + (int) $someVal;
    }

    public function __get($prop) { return 42; }

    public function __set($prop, $value) {
        echo('Setting ' . $prop . ' with ' . $value);
    }

    public function __toString() { return 'MyClass'; }
}

$myClass = new MyClass();
echo('Instance? ' . ($myClass instanceof Iface) . "\n");
//call static
$a = MyClass::getFileContents();
//call normal
$myClass->write('Hey');
//invoke
$b = $myClass(20);
$c = $myClass('15');
//trigger getter/setter
$d = $myClass->someProp;
$myClass->someNewProp = 20;
//string version
$e = strval($myClass);

Ambient class, interface, variable, and function declarations are not emitted with the PHP output. They are best suited for describing external code. To make a variable, class, or function ambient, simply use the declare keyword before it. To make an interface ambient, make the interface explicitly extend Pct.Ambient. Another way to make all of these ambient is to simply place them in a declaration file (which is a file that has the .d.ts extension). For example, here are the contents of json.d.ts which describes the JSON library:

var JSON_ERROR_CTRL_CHAR: number;
var JSON_ERROR_DEPTH: number;
var JSON_ERROR_NONE: number;
var JSON_ERROR_STATE_MISMATCH: number;
var JSON_ERROR_SYNTAX: number;
var JSON_ERROR_UTF8: number;

var JSON_BIGINT_AS_STRING: number;
var JSON_FORCE_OBJECT: number;
var JSON_HEX_AMP: number;
var JSON_HEX_APOS: number;
var JSON_HEX_QUOT: number;
var JSON_HEX_TAG: number;
var JSON_NUMERIC_CHECK: number;
var JSON_PRETTY_PRINT: number;
var JSON_UNESCAPED_SLASHES: number;
var JSON_UNESCAPED_UNICODE: number;

interface JsonSerializable {
    jsonSerialize(): any;
}

function json_decode(json: string, assoc?: bool, depth?: number, options?: number): any;
function json_encode(value: any, options?: number): string;
function json_last_error(): number;

Since ambient types are still seen at runtime, they will be emitted as type hints. Compile-time declarations do not suffer from this. They are only there to enforce a certain contract and that's it. Only interfaces and classes can be marked compile-time only, and this is done by explicitly extending or implementing the Pct.CompileTimeOnly interface. Just because a super class/interface implements Pct.CompileTimeOnly doesn't mean it's children do, it must be explicitly stated.

interface Place extends Pct.CompileTimeOnly {
    zip: string;
    city?: string;
}

interface Weather extends Pct.CompileTimeOnly {
    place: Place;
    temperature: number;
}

function printWeather(weather: Weather) {
    echo('It is ' + weather.temperature + ' in ');
    if (property_exists(weather.place, 'city')) {
        echo(weather.place.city);
    } else echo(weather.place.zip);
}

printWeather({
    place: {
        zip: '75001',
        city: 'Addison'
    },
    temperature: 85
});
printWeather({
    place: {zip: '76020'},
    temperature: 88
});










function printWeather($weather) {
    echo('It is ' . $weather->temperature . ' in ');
    if (property_exists($weather->place, 'city')) {
        echo($weather->place->city);
    } else echo($weather->place->zip);
}

printWeather((object)[
    'place' => (object)[
        'zip' => '75001',
        'city' => 'Addison'
    ],
    'temperature' => 85
]);
printWeather((object)[
    'place' => (object)['zip' => '76020'],
    'temperature' => 88
]);

Modules in Pratphall are directly translatable as namespaces in PHP.

Even though PHP namespaces cannot be nested, Pratphall modules can. When emitted to PHP, they are separated. The dots translate to slashes in PHP. When not in the global namespace, globally namespaced type references are automatically prefixed with a slash.

If a module is imported with an alias, it is translated to a use statement. If the alias is the same as the last module part, the as alias in the use statement is not emitted. Currently, Pratphall can only import and alias other modules, there is no importing or aliasing of other classes/interfaces. The namespace operator to access something in the same module is not present in Pratphall.

External module references that use import mod = module('modname') format cause a compiler warning and are ignored for now. Use of the export feature to share items amongst modules/namespaces is strictly a compile-time feature and is not emitted to PHP.

If you must reference code in another file, you can use ///<reference path="PATH" />. It is common practice to reference a file that might just be full of references to the other files in the project. This is just a compile-time reference unless both --no-organize and --require-references are set as compiler options.

Different compiler options affect how the files are outputted. Below are descriptions of the options and output PHP examples based on these two files:

//file1.ts
module MyModule {
    export interface MyIface {
    }

    export module Sub {
        export class MyClass implements MyModule.MyIface {
            causeErr() {
                throw new Exception('Error');
            }
        }
    }
}

//file2.ts
///<reference path="file1.ts" />
import Sub = MyModule.Sub;
var a = new Sub.MyClass();
a.causeErr();
default
By default, all classes and interfaces are written into their own file according to PSR-0. This means that except for the initial file passed to the compiler, no other files may have any top-level vars/functions or be in the global namespace.
//MyModule/MyIface.php
namespace MyModule;

interface MyIface {
}

//MyModule/Sub/MyClass.php
namespace MyModule\Sub;

class MyClass implements MyModule\MyIface
    public function causeErr() {
        throw new \Exception('Error');
    }
}

//file2.php
use MyModule\Sub;
$a = new Sub\MyClass();
$a->causeErr();
with --no-organize
When this option is set, all emitted PHP files are the same name as the Pratphall source files (.ts files) but with PHP extensions. This cannot be used with --single since that option basically includes this option. This option allows top-level code in any file and allows any file to operate in the global namespace. This option is best used in conjunction with --require-references. When that option is set, the ///<reference path="PATH" /> references become require_once calls in PHP.
//file1.php
namespace MyModule {

    interface MyIface {
    }

}

namespace MyModule\Sub {

    class MyClass implements MyModule\MyIface
        public function causeErr() {
            throw new \Exception('Error');
        }
    }

}

//file2.php
use MyModule\Sub;
$a = new Sub\MyClass();
$a->causeErr();
with --single
When this option is set, all Pratphall code is emitted to a single PHP file. Like the default, this means that except for the initial file passed to the compiler, no other files may have any top-level vars/functions. However, any file can have contents in the global namespace. This cannot be used with --no-organize.
//file2.php
namespace MyModule {

    interface MyIface {
    }

}

namespace MyModule\Sub {

    class MyClass implements MyModule\MyIface
        public function causeErr() {
            throw new \Exception('Error');
        }
    }

}

namespace {
    use MyModule\Sub;
    $a = new Sub\MyClass();
    $a->causeErr();
}

Pratphall includes the ability to write compile-time extensions that can emit PHP code, validate input, or do anything else. They are written in TypeScript (not Pratphall) and run during compilation in nodejs.

Extensions utilize the AST structure built in to the TypeScript code base. The most common use of extensions is to emit PHP that isn't available in Pratphall. In fact, all of the Pct features are implemented as extensions and can be seen in the Pratphall source in the src/ext folder. For example, here is the extension source that turns toString calls in Pratphall to strval calls in PHP:

///<reference path='../pratphall.ts' />

module Pratphall {
    import TS = TypeScript;

    PhpEmitter.registerExtension({
        name: 'Object.toString emitter',
        description: 'Make it strval',
        matcher: {
            nodeType: [TS.NodeType.Call],
            priority: 1,
            propertyMatches: {
                target: (value: TS.AST): bool => {
                    return value instanceof TS.BinaryExpression &&
                        value.nodeType == TS.NodeType.Dot &&
                        (<TS.BinaryExpression>value).operand2 instanceof TS.Identifier &&
                        (<TS.Identifier>(<TS.BinaryExpression>value).operand2).text == 'toString';
                }
            }
        },
        emit: (ast: TS.CallExpression, emitter: PhpEmitter): bool => {
            emitter.write('strval(').emit((<TS.BinaryExpression>ast.target).operand1).write(')');
            return true;
        }
    });
}

There are several things to note here about the extension API. First, is the reference to pratphall.ts. This is just a directory above where this extension is. However, in your project where you may reference Pratphall locally in your package.json, it might be at node_modules/pratphall/src/pratphall.ts. Note, at the present extensions cannot reference other arbitrary TypeScript, it should all be self contained in the extension file.

Next, this extension happens to be in the Pratphall module, but yours can be in any. The PhpEmitter class has a static method called register extension that takes a single object. This object must have a name, a description, a matcher object, and an emit function. The name and description are unused currently, but provide metadata about the extension.

The matcher is an object that matches AST so the emitter knows when to invoke the extension. The nodeType property is an array of node types this extension accepts. You will have to reference the TypeScript source code to see what these node types are. The priority property is a numeric value which defines the order in which the extension is executed. The higher the priority, the earlier it will be executed. All built-in Pratphall extensions use a priority of 1. Finally there is the propertyMatches property. This property is simply a collection of functions bound to names of properties on the AST object you are targeting. The function will be called with that property as the parameter and you must return true for it to be handled. In the above example, this checks that it is a dotted binary expression whose right hand side is the toString function (e.g. something.toString).

The emit function accepts the AST and the PHP emitter as parameters. Again, you may have to look at the TypeScript and Pratphall source to understand these. The emitter offers several functions to help emit PHP. If the function returns true, no more extensions for this AST node will be executed. If it returns false, other extensions down the priority chain will be executed. If no extensions match an AST node, it is emitted normally.

Let's say you wanted to make an extension that ran some code that was output buffered and then flushed the buffer at the end. In PHP you do this with ob_start and ob_end_flush. On the Pratphall side, you will want to create a compile-time function to help with this. Then you can use it in Pratphall:

//create a module with a declared (ambient) function
//NOTE: this could also be a class w/ a static function or anything
module Output {
    declare function bufferThenFlush(code: () => void);
}

//now use it
Output.bufferThenFlush(() => {
    //buffer this!
    echo('blah');
});

So now we must make an extension in TypeScript. Let's assume our extension is at src/myext.ts. Here is what it might look like:

///<reference path='../node_modules/pratphall/src/pratphall.ts' />

module MyExt {
    import TS = TypeScript;

    PhpEmitter.registerExtension({
        name: 'Output.outputThenFlush',
        description: 'Handle output-then-flush handler',
        matcher: {
            nodeType: [TS.NodeType.Call],
            priority: 5,
            propertyMatches: {
                target: (value: TS.AST) => {

                    //isDottedBinEx is a helper available to you to check a dotted binary expression
                    return Pratphall.isDottedBinEx(value, 'Output', 'outputThenFlush');
                }
            }
        },
        emit: (ast: TS.CallExpression, emitter: PhpEmitter): bool => {

            //first grab the argument
            var arg = ast.arguments.members[0];

            //let's make sure it's an anonymous function declaration
            if (!(arg instanceof TS.FuncDecl) || !(<TS.FuncDecl>arg).isAnonymousFn()) {
                emitter.addError(arg, 'Argument must be an anonymous function');
                //return true saying we've handled this (will skip emit)
                return true;
            }

            //let's start the output buffering
            emitter.write('ob_start();').newline();

            //now we need to take the body of the function and emit it directly
            var func = <FuncDecl>arg;
            //emitBlockStatements is a helper...otherwise, a normal emit() can be used for AST's
            //the true means we want newlines before each statement
            emitter.emitBlockStatements(func.bod, true);

            //now end and flush
            //notice we omit the ending semi-colon...that is because this was originally
            //  a statement and all statements receive a semi-colon already; so after this is
            //  written a semicolon and newline is automatically added just like if this extension
            //  was never executed
            emitter.newline().newline().write('ob_end_flush()');

            //return true to say we've handled it
            return true;
        }
    });
}

That's all there is to it. Now when running ppc, you can pass --ext src/myext.ts and the code that used the ambient function will look like this.

ob_start();

//buffer this!
echo('blah');

ob_end_flush();

Extensions are also a good way to write validators. Simply do your checks and add errors or warnings in the emit function. You can return true on errors to skip emitting or false to continue. There are many examples of extensions in the Pratphall source at src/ext. Even dust-php uses an extension in the test/ folder that takes some JSON and makes test cases out of it. It is a complex subject, but working through a few will make it easier to understand.

This is neat, so I can convert my PHP programs to JavaScript/TypeScript? Can I convert my JavaScript/TypeScript programs to PHP?
No and no (basically). The goal of this project is to provide a new language that emits PHP. Pratphall intentionally doesn't convert existing code because it would put too many constraints on the language's freedom and would require a significant runtime layer which is unacceptable.
Well, can you generate the ambient declarations from existing PHP code with strong PHPDoc blocks? Or maybe generate PHPDoc annotations when emitting?
In theory, ambient declarations could be generated from existing PHP code. Also, PHPDoc annotations could be generated during compilation. The problem is that PHPDoc and Pratphall's typing systems don't lineup very well. For example, PHPDoc doesn't support differentiating between numerically indexed arrays and associative arrays. And Pratphall doesn't support knowing whether a value is nullable or not (e.g. the string|null PHPDoc type).
Ok, then can I at least write Pratphall code that can also run in a JavaScript environment?
Technically, yes. Many features of JavaScript/TypeScript are supported. If you are careful and abstract properly, some of your Pratphall code can also run in a browser. For instance, imagine you had a bunch of model objects that are serialized to and from JSON for use in RESTful API calls. If you needed the server side to have these models for processing and the client side to have them for an AJAX call, you could share the Pratphall model code.
How does this effort relate to php.js? Can I use it?
Pratphall has not been tested with php.js in any way whatsoever, so use at your own risk. Though, in theory there are two ways Pratphall and php.js can work together. Firstly, if you were targeting both a JS environment and PHP, php.js has runtime support for many of the PHP functions you may need in both environments. Secondly, Pratphall supplies typed definitions for all PHP functions which means even if you're not developing in Pratphall and instead just developing in TypeScript, you now have a typed set of definitions for all the phpjs functions.
You are almost there for supporting the entire language of JavaScript/TypeScript, why not support it 100%? Then you can bootstrap Pratphall in PHP too.
This would require too much runtime support since certain features of JavaScript/TypeScript have no equivalent in PHP. It is possible that an ancillary fork of Pratphall may aim to support the entirety of JavaScript/TypeScript, but it will be as an extension because Pratphall's goal is to compile to readable, minimal, and predictable PHP.
What is the minimum PHP version Pratphall supports?
Currently, it is PHP 5.4. Several features (mainly short array syntax and closures w/ $this) are required. If you use finally in your try blocks, then PHP 5.5 is required. This decision was made since Pratphall is a new language and should not be bound by older environments. It is possible that 5.3 will be supported with a compiler option if there is enough need.
I have heard that "transpiled" languages suffer from debugging issues. How do you debug code in Pratphall?
Currently there is no easy method to debug Pratphall in your favorite editor. If the Visual Studio protocol was more public and friendly (i.e. not COM/DCOM) we could write a proxy to convert Xdebug events to Visual Studio events (if anyone can help here, we'd appreciate it). If node-inspector accepted source mapping (ref issue 100) we could possibly proxy the Xdebug events to V8 protocol. Or if CATS had integrated debugging w/ V8 protocol, we could do it there too (ref issue 6). Maybe the best idea is to combine the source map support in Chrome Canary and the remote debugger protocol and use Chrome's devtools as the client (maybe embedded via node-webkit). But for now, there is no direct debugging.
How complete is this? Should I depend on it for production code?
It is fairly complete, however TypeScript itself is still only in preview. They might implement new features or change existing ones which can affect Pratphall. Using for production code shouldn't be a problem since the language is cross-compiled and the PHP is easily readable and auditable. The only real problem comes from backwards incompatibilities from Pratphall being unstable. Pratphall's first stable release will not be before TypeScript's first stable release (and maybe well after, depending).

Stronger built-in Visual Studio support will be coming soon in Pratphall, but for now it's fairly limited. Having said that, it is still the most complete IDE for Pratphall. Visual Studio Express 2012 for Web is free and it was the IDE used to create Pratphall. When using Visual Studio, it is recommended to use --no-php-lib when compiling and add a reference to php.d.ts (in the bin directory of installation) to a commonly referenced base. This will give intellisense support and all normal Visual Studio features.

There are a few reported errors from the TypeScript compiler that Pratphall suppresses. These will appear as errors in Visual Studio, but are not Pratphall errors. They are:

Despite the above, using Visual Studio is well worth it. Besides the refactoring and search capabilities, you also get intellisense:

Building from source is done very easily. You must have nodejs installed. Then, clone the git repository (using --recursive to get the TypeScript submodule):

git clone --recursive https://github.com/cretz/pratphall.git
Now navigate into the newly created pratphall directory and run npm install to resolve the development dependencies:
npm install
This will install Jake, TypeScript, and a few other items locally. Now run the build task with local Jake (or the global version if you already have Jake installed):
node_modules/.bin/jake build
This will compile everything into a single JS and move everything to the bin directory. You can also run the test cases very easily:
node_modules/.bin/jake test

A configuration file can be passed in to ppc using the -c or --config option. It contains all the same features as the command line options, but sometimes worded differently. When a configuration file is specified, it overwrites any command line parameters that may appear before it. If there are command line parameters after the configuration file parameter, they will override configuration options. Here is the TypeScript class definition (with defaults) the JSON values are merged into:

class CompilerOptions {
    //whether or not to emit comments on output
    comments = true;

    //whether or not to exclude emitting files above/outside
    //of the input file's directory
    excludeOutside = false;

    //array of extension .ts files to be loaded
    extensions: string[] = [];

    //if true, makes all single line if, while, etc
    //statements have a block for their contents
    forceBlock = false;

    //if true, forces the opening brace of any function
    //(non closure) declaration to start on the next line
    // by itself
    functionBraceNewline = false;

    //the number of times to indent per depth, usually best at 1
    //if indentSpaces is false (meaning using tabs)
    indentCount = 4;

    //if true, indent with spaces; if false, indent with tabs
    indentSpaces = true;

    //whether or not to include TypeScript's lib.d.ts
    jsLib = true;

    //if true, parse/compile only, do not emit output files
    lint = false;

    //if true, organize source into PSR-0-style type-per-file
    organize = true;

    //the individual file or directory to output to
    out: string = null;

    //whether or not to include the php.d.ts runtime lib automatically
    phpLib = true;

    //if true, will always use single quotes unless there is
    //an escape character
    preferSingleQuotes = false;

    //if true, Pratphall reference's will become require_once statements
    requireReferences = false;

    //if true, emits a single PHP file with all source
    single = false;

    //if true, forces the opening brace of any class or interface
    //declaration to start on the next line by itself
    typeBraceNewline = false;

    //if false, do not emit type hints on any functions in the output
    typeHint = true;

    //if false, use "else if" instead of "elseif"
    useElseif = true;

    //if true, output lots of extra information during compile
    verbose = false;

    //if true, run as daemon, watching for changes on any referenced
    //files and triggering a smart recompile
    watch = false;

    //the number of milliseconds after the last file change event
    //to start the smart recompile
    watchDebounceMs = 1500;
}

Here is an example of a configuration that complies mostly with PSR-2:

{
    "forceBlock": true,
    "functionBraceNewline": true,
    "indentCount": 4,
    "indentSpaces": true,
    "organize": true,
    "typeBraceNewline": true,
    "useElseif": true
}

Below are gotchas that might not be expected during development

001: Pratphall can't tell whether it's invoking an object's method or object's property that's a closure
Unfortunately if you have an object property that's a closure in PHP, you cannot invoke it like $obj->property();, you have to do something like $obj->property->__invoke();. Sometimes there isn't enough typing information to determine whether a method invocation is a closure on a property or a method on an object. Therefore, Pratphall has to emit something like (method_exists($obj, 'property') ? $obj->property() : $obj->property->__invoke());. In order to avoid this, make sure your types are strong so the engine can tell which is which.
002: Pratphall doesn't support naming properties/variables and methods/functions the same, making declarations for external PHP w/ name ambiguities difficult
Any time you want name ambiguity in your PHP code, simply use an extra underscore at the end of either identifier in Pratphall. Any identifier that doesn't start with an underscore, but ends with one will have the ending underscore removed in translation.
003: the JS arguments variable that gets the function arguments is unavailable if redefined later in function
Basically, if you use the arguments array, then create a var later in the same function named arguments, we cannot tell the one used above the re-declaration needs func_get_args. Basic rule of thumb is not to use the arguments array in a function unless you have to, and then don't redefine it in the function.
004: String.charCodeAt only uses ord when emitting
Even though String.charCodeAt supports unicode in JS, we only use ord. Please handle unicode needs separately.
005: String.indexOf emits more than just strpos.
Due to the fact the JS one returns -1, the emitter emulates that. To avoid this, just call strpos directly.
006: Regular expressions are flat out unsupported
JS and PHP's regular expression syntaxes differ too much to support right now
007: String.replace doesn't support callback
There is no str_replace_callback in PHP, only a regex version
008: String.slice and String.substring are unsupported
Although negatives work the same for end and length in slice and substr, there is not an easy way to determine negative. Same issue with converting from end to length. It would require too much runtime support on the PHP side.
009: String.toLocaleLowerCase and toLocaleUpperCase are unsupported
There is no guarantee that mb_ functions are available
010: Object.valueOf is unsupported
No equivalent in PHP
011: Many Object functions (e.g. freeze) are unsupported
No equivalents in PHP, but no errors emitted because they can be overridden
012: Array.reverse is unsupported
No equivalent in PHP that alters the array instance
013: Array iteration functions don't really support second parameter "this"
The only value allowed as a second parameter in an array iteration function is literal "this".
014: Array.every is unsupported
No PHP equivalent
015: Array.indexOf is unsupported
array_search can't support fromIndex, would have to be strict, and would require too much runtime support to make false return -1.
016: Array.join assumes comma by default
A comma is used as the glue for implode if not specified.
017: Array.lastIndexOf is unsupported
No PHP equivalent
018: Array.reduceRight is unsupported
No PHP equivalent
019: Second parameter of Array.slice is unsupported
No PHP equivalent
020: Array.some is unsupported
No PHP equivalent
021: Second parameter of JSON.parse is unsupported
No PHP equivalent
022: Second and third parameters of JSON.stringify are unsupported
No PHP equivalent
023: Class/interface names cannot be the same as module/namespace names at the same level
This is common practice in PHP especially before namespaces were introduced. We believe this lack of support will actually help properly group types instead of using namespaces as OOP extension paths. Any time you want name ambiguity in the PHP code, an underscore can be added to the end of any identifier and (assuming the identifier doesn't start with an underscore), it will be removed.

These are some wishlist items that could be implemented in the future.

These are some items that need to be fixed.

0.1.0
Initial release