
Distinctive Features of the PH7 Engine.
The following page enumerates distinctive features and powerful extensions introduced by the PH7 Engine to the PHP programming language, these are:
Full Type hinting (function signatures).
Introducing comma expressions.
Introducing the eq and ne operators for strict string comparison.
Function arguments can take any complex expressions as their default values.
64-bit integer arithmetic for all platforms.
Static variables and constants can take any complex expression including function call as their initialization value.
No fatal error, even a call to an undefined function will not abort program execution.
Very high code quality.
Arrays like object are always passed and returned by reference.
PH7 is 100% hand-coded, written in ANSI C, compile and run unmodified in any platform including restricted embedded devices with a C compiler.
Amalgamation: All C source code for PH7 are combined into a single source file.
Powerful reference mechanism borrowed from the C++ world.
Standard functions can take a single statement without curly braces.
Anonymous functions can be invoked on the fly without any kind of assignment.
Anonymous functions arguments can take default values (Any complex expression).
Anonymous functions can embed static variable.
Language constructs such as echo, print, include, etc. can be used in the context of a function call.
Introducing floating point comparison.
Consistent Boolean evaluation.
Built-in sorting function such as sort(), usort(), ksort() and many more uses the efficient and stable merge-sort algorithm.
Smart exception mechanism.
Garbage Collected via Advanced Reference Counting.
Thread-safe (via compile-time directive) and full re-entrant.
Highly-efficient and platform independent Byte-code compiler.
Built with more 470 function including an XML parser (with namespace support), INI processor, CSV reader/writer, UTF-8 encoder/decoder, zip archive extractor, JSON encoder/decoder, random number/strings generator, native and efficient File IO for Windows and UNIX systems and many more without the need of any external library to link with.
Efficient implementation of arrays using the hashmap data strcuture.
Array cursor is automatically reset at the end of a foreach loop.
const statement can be used outside a class definition.
var statement can be used outside a class definition.
Automatic switch to pass by value when a invalid pass by reference is detected.
Correct and consistent implementation of the ternary operator.
Constants can be redefined using the define() function.
Parameters to call_user_func() can be passed by reference.
Insertion by reference now support function calls.
implode() can take a variable number of arguments (even non-array).
explode() does not return empty (white space stream) entries.
Introducing the implode_recursive() and join_recursive functions().
Platform independent and efficient implementation of the printf() family of function (Based on the SQLite3 implementation)
Introducing the str_glob() function fro string globing.
Introducing the $_HEADER superglobal array which hold all HTTP REQUEST MIME HEADERS
- Caveats.
Features in details
We describe now, some of the important PH7 features in details.
Function Overloading
Function overloading or method overloading is a feature found in various programming languages such as C++ or Java, that allows creating several function and/or methods with the same name which differ from each other in the type of the input and the output of the function. It is simply defined as the ability of one function to perform different tasks. (src: Wikipedia)
Function overloading means two or more functions can have the same name but either the number of arguments or the data type of arguments has to be different.
The PH7 engine introduces this powerful mechanism as an extension to the PHP programming language. That is, you define two ore more standard PHP functions with the same name (PH7 is case-sensitive unlike the standard PHP engine) but with different arguments number and/or types and finally you perform a simple function call and let PH7 peek the appropriate function for this call context.
Example: (Overloading without the full type hinting extension)
//foo() accepts only a single argument
return $a.PHP_EOL;
}
function foo($a, $b) {
// foo() accepts two arguments and perform their addition.
return $a + $b;
}
echo foo(5); // Prints "5"
echo foo(10, 2); // Prints "12"
Here, we define two functions with the same name but with different purposes. That is, the first foo() accepts only a single argument and return its value while the second foo() accepts two arguments, perform their addition and return the result. So if we call foo with a single argument the first foo() will be invoked while if we call foo with two or more arguments,the second foo() will be invoked.
Example 2: (Overloading With the full type hinting extensions)
{
echo "a is a string\n";
var_dump($a);
}
function foo(int $a)
{
echo "a is integer\n";
var_dump($a);
}
function foo(array $a)
{
echo "a is an array\n";
var_dump($a);
}
/* Test the mechanism */
foo('This is a great feature'); /* a is a string (first foo) */
foo(52); /* a is integer (second foo) */
foo(array(14,__TIME__,__DATE__)); /* a is an array (third foo) */
Here, we define three functions with the same name and the same number of arguments but with different signatures. That is, each function accepts a single argument but with a different type than the others. This was possible by the powerful full type hinting extension introduced by the PH7 engine which permit functions to have their own signatures. So if we call foo with a string argument as follows foo('This is a great feature'); The first foo() that expect a string argument will be invoked while if we call foo with a array argument as follows foo(array(14,__TIME__,__DATE__)); the last foo() that expect a array will be invoked.
Example 3: (Wikipedia example ported to PH7 PHP)
function volume(int $s)
{
return $s*$s*$s;
}
// volume of a cylinder
function volume(float $r,int $h)
{
return 3.14*$r*$r*$h;
}
// volume of a cuboid
function volume(float $l,int $b,int $h)
{
return $l*$b*$h;
}
/* Test the overloading mechanism */
echo volume(10).PHP_EOL; /* You should see 1000 */
echo volume(2.5,8).PHP_EOL; /* You should see 157 */
echo volume(100,75,15); /* You should see 112500 */
Again, three functions with the same name but each one expects a different number and different types of arguments, PH7 is smart enough to peek the appropriate function for the call context.
Example 4: (With Class methods)
public static function foo($a) {
return $a.PHP_EOL;
}
static function foo($a, $b) {
return $a + $b;
}
}
$c = new a();
echo $c->foo(rand()&1023); //print a random number
echo $c->foo(25,50); //print 75
Function overloading is not restricted to standard PHP function, you can also make your class methods candidate for overloading exactly like standard function would do. As a bonus side, overloading apply also to class constructors. That is, define a class with two or more constructors but with different signature and let PH7 peek the appropriate constructor for you.
Example:
function __construct($a) {
echo $a.PHP_EOL;
}
function __construct($a, $b) {
echo $a + $b;
}
}
$c = new a(150); /* You should see: 150 */
$c = new a(60,200); /* You should see: 260 */
Full Type Hinting
PHP 5 introduces type hinting. Functions are now able to force parameters to be only objects (by specifying the name of the class in the function prototype), interfaces or arrays (since PHP 5.1).
PH7 goes further and extends the type hinting mechanism to be used with scalar types such as string, int, float or even the Boolean type.
With type hinting, arguments are automatically and silently converted to the desired type. By doing so there is no need to add the ugly test statements at the beginning of function prolog to check for the expected argument types using the is_string(), is_float(), etc. functions. All of this is done automatically by the engine freeing the programmer from a boring task.
Example: Type hinting with scalar values (string).
{
var_dump($a);
}
/* Call with a string argument */
test("Hello world"); //Output string(11 'Hello world');
/* Call with an int argument */
test(0xFFFFFFFF); //Output string(10 '4294967295');
/* Call with a float argument */
test(25.e-1); //Output string(3 '2.5');
Here if we call the test() function with an int argument, an automatic cast is performed and the given integer value (hexadecimal 0xFFFFFFFF) is converted to a decimal number (4294967295) first, then a string cast is performed. The same operation is done if we call test() with a float argument. The float number is converted to a string and the result is outputted (2,5).
Example 2: Type hinting with scalar values (integer)
{
var_dump($a);
}
/* Call with a string argument */
test(" 256garbage"); //Output int(256);
/* Call with a float argument */
test(14.52e+2); //Output int(1452)
Again, before dumping the result, PH7 internally convert the given argument to the type integer. So if we call our test function with a string argument, this parameter gets converted to the best representation of an integer. That is, the conversion stops at the first character that is not a digit or a hexadecimal character (white space is completely ignored).
We
recommend to the PH7 enthusiastic users to experiment with this
powerful mechanism and to report any unexpected result or
inconsistency and/or their feedback to the PH7
public forums or using the PH7
mailing list.
Comma expressions
Again, another powerful mechanism borrowed from the C/C++ world and introduced as an extension to the PHP programming language.
A comma expression contains two operands of any type separated by a comma and has left-to-right associativity. The left operand is fully evaluated, possibly producing side effects, and its value, if there is one, is discarded. The right operand is then evaluated. The type and value of the result of a comma expression are those of its right operand, after the usual unary conversions.
Any number of expressions separated by commas can form a single expression because the comma operator is associative. The use of the comma operator guarantees that the sub-expressions will be evaluated in left-to-right order, and the value of the last becomes the value of the entire expression.
The following example assign the value 25 to the variable $a, multiply the value of $a with 2 and assign the result to variable $b and finally we call a test function to output the value of $a and $b. Keep-in mind that all theses operations are done in a single expression using the comma operator.
/* Output the value of $a and $b */
function test(){
global $a,$b;
echo "\$a = $a \$b= $b\n"; /* You should see: $a = 25 $b = 50*/
}
The primary use of comma expressions is to produce side effects in the following situations:
Calling a function
Entering an iteration loop
- Testing a condition
In some contexts where the comma character is used, parentheses are required to avoid ambiguity.
The following table gives some usage example of comma expressions.
if(++$x,$y = 100, $x > $y,foo()) function foo(){ return TRUE; } |
An if statement in which, variable $x is incremented, variable $y is assigned the value 100 and variable x is tested against variable $y and finally function foo()gets called. The first two expressions within this comma expression are evaluated before the call to foo(). Regardless of the results of the first three expressions, the fourth is evaluated (call to function foo()) and its result determines whether the if statement is processed. |
We recommend to the PH7 enthusiastic users to experiment with this powerful mechanism and to report any unexpected result or inconsistency and/or their feedback to the PH7 public forums or using the PH7 mailing list.
Introducing the eq and ne operators.
The eq and ne operators are borrowed from the Perl world. They are used for strict string comparison. The reason why they have been implemented by the PH7 engine and introduced as an extension to the PHP programming language is due to the confusion introduced by the standard PHP comparison operators ('==' or '===') especially if you compare strings with numbers.
Take the following example:
// use the type equal operator by adding a single space to one of the operand
var_dump( '255 ' === '255' ); //bool(true) depending on the PHP version
That is, if one of the operand looks like a number (either integer or float) then PHP will internally convert the two operands to numbers and then a numeric comparison is performed.
This is what the PHP language reference manual says:
If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically.
Bummer,
if you ask me, this is broken, badly broken. I mean, the programmer
cannot dictate it's comparison rule, it's the underlying engine who
decides in it's place and perform the internal conversion. In most
cases, PHP developers wants simple string comparison and they are
stuck to use the ugly and inefficient strcmp() function or it's
variants instead. This
is the big reason why we have introduced these two operators.
The eq operator is used to compare two strings byte per byte. If you came from the C/C++ world, think of this operator as a barebone implementation of the memcmp() C standard library function. Keep in mind that if you are comparing two ASCII strings then the capital letters and their lowercase letters are completely different and so this example will output false.
The ne operator perform the opposite operation of the eq operator and is used to test for string inequality. This example will output true
The eq operator return a Boolean true if and only if the two strings are identical while the ne operator return a Boolean true if and only if the two strings are different. Otherwise a Boolean false is returned (equal strings).
Note that the comparison is performed only if the two strings are of the same length. Otherwise the eq and ne operators return a Boolean false without performing any comparison and avoid us wasting CPU time for nothing.
Keep in mind that we talk about low level byte per byte comparison and nothing else. Also remember that zero length strings are always equal.
Some example and their outputs:
//Append a single space to the first operand
var_dump(' 255 ' eq '255'); //bool(FALSE) Not of the same length
//Operand one is a prefix of the second.
var_dump('TES' eq 'TEST'); //bool(FALSE) What do you expect!
var_dump('A7lan' eq 'A7lan'); //bool(TRUE)
// Test the not equal 'ne' operator
var_dump( '255' ne 0xFF ); //bool(TRUE)
//Append a single space to the first operand
var_dump(' 255 ' ne '255'); //bool(FALSE) (Not of the same length)
Improved Operators Precedence Table
PH7
implements all the 60 PHP operators and introduced the eq
and ne operators. The operators precedence table have been
improved dramatically so that you can do same amazing things now such
as array dereferencing, on the fly function call, anonymous function as
array values, class member access on instantiation and so on. We
discuss some of the improvements in details:
Array Dereferencing:
With this improvements, there is no need for a temporary variable to extract array entries values. Let's just say you want to output the middle name of Alan Mathison Turing in one statement without any assignment:
echo
explode(
'
'
,
'Alan
Mathison Turing
')[1];
//Output:
Mathison
As you can see, there is no need for a temporary variable, the entry value was extracted by dereferencing the array returned by the explode() built-in function. You can even extract array values directly from functions return value as follows:
return array( 'Machine' => 'Turing');
}
//Call the test function and output the 'Machine' entry value without any assignment
echo test()['Machine']; //Output: Turing
More, you can even insert anonymous functions in a array and invoke them directly as follows:
return array( 'Anon' => function(){echo "Hello World\n";});
}
//Invoke the anonymous function stored in the 'Anon' entry from the returned array
echo test()['Anon'](); //Hello World
Anonymous Functions as Array Values
As of this release, you can insert anonymous function in a array and invoke them on the fly or assign them to a variable as follows:
'add' => function ($x,$y){ return $x+$y; },
'mul' => function ($x,$y){ return $x*$y; },
'div' => function ($x,$y){ return $x/$y; }
);
/* Extract the anonymous function performing an addition */
$add = $a['add'];
/* Invoke */
echo $add(100,200); //Output: 300
/* Invoke our anonymous function directly by dereferencing the array */
echo $a['add'](50,20).PHP_EOL; //Addition: Output 70
echo $a['mul'](10,20).PHP_EOL; //Multiplication: Output 200
echo $a['div'](50,2); //Division: Output 25
Here, the test array hold three anonymous functions. All of them expects two arguments and all perform an arithmetic operation. The first anonymous function perform an addition and it's associated key in the array is add, the second perform a multiplication and its key is mul while the third perform a division and it's key is div. If we call one if them either on the fly or via variable assignment, you will get the result of the desired arithmetic operation (addition, multiplication or division).
Class Member Access On Instantiation
With this improvements, you can access to class attributes without assigning the instantiated class to a variable as follows:
public $attr = 'Some '.'Value'; // Complex expression: Concatenation of two strings: Some + Value
};
//Access the class member without assigning the instantiated class to a variable
echo (new Test())->attr; //You should see: Some Value
We have outputted the class attribute value without any kind of assignment. The garbage collector subsystem will automatically release this instance since it will not be used anywhere.
Powerful OO Subsystem
PH7 implements most of the PHP(5) OO subsystem including standard classes, interfaces, inheritance, magic methods, cloning, abstract and final methods, constructors and destrcutors, type hinting and so on. PH7 goes further and introduces some powerful extensions to the OO subsystem and we list some of the important extensions here:
-
Class attributes including variable, static variables and constants can take any complex expressions as their initialization value unlike the standard PHP engine which would allow only simple scalar value. Example : (Complex initialization value)
class MyClass {
const RAND_NUM = rand() & 1023 ; //Random number between 0 and 1023
public $var = 'Var: '.rand_str(6); //Concatenate 'Var: ' and a random string of length 6
}
$c = new MyClass();
var_dump($c::RAND_NUM,$c->var); //You should see a random number and a random string
Constructors and Destructors are candidate for overloading exactly like any other class methods.
If no constructor is available, attributes will keep their initialization values (any complex expressions) and will not be nullified.
-
Static properties can be accessed and modified through the object using the arrow operator as follows:
class MyClass {
public static $a = 5*5;
}
$n = new MyClass;
$n->a <<= 1;
echo MyClass::$a; /* Will output 50 */
Introducing magic methods __toInt(), __toBool(), __toFloat() which performs the same job as the __toString() magic method but for their types respectively Integer, Boolean and Float.
clone now accepts a function(including anonymous) or an instantiated class (object) as it's left operand as follows:
$pCopy = clone obj(); // function obj(){ return new Class(); }
$pCopy = clone $a['object']; // $a = array('object' => new Class());
//Annonymous function
$pCopy = clone (function (){ return new SomeClass(); })();
A class may not implement all the methods declared inside an interface.
A class can implement two interfaces that share same methods names as follows:
interface IA {
public function a();
}
interface IB {
public function a();
}
class Test implements IA, IB {
public function a() {
echo "Hello World";
}
}
$o = new Test();
$o->a(); //Hello World
OO
Caveats:
-
PH7 does not handle all the magic methods such __wakeup(), __sleep(), __set_state(), __serialize() and __unserialize().
Object serialization is avoided. If you want to serialize an object, use the built-in json_encode() function.
64-Bit Integer Arithmetic For All Platforms
Under the standard PHP engine, The size of an integer is platform-dependent which mean that when running on 32-bit systems, the size of an integer is stored in 4 bytes and 8 bytes on 64-bit systems. This lead to non portable code especially if you are working with large integers. PH7 have standardized this and integers now are stored in 8 bytes (64 bits) regardless of the host environment. Because there is no cross-platform way to specify 64-bit integer types PH7 includes typedefs for 64-bit signed integers. The ph7_int64 type can store integer values between -9223372036854775808 and +9223372036854775807 inclusive.
Example:
If you run this example on 32-bit or 64-bit (Windows or UNIX) systems, you will get the same output as follows: 8 9223372036854775807
Complex expressions for arguments default values
While the standard PHP engine would allow simple scalar values for function arguments default values, PH7 goes further and let you use any complex expressions including function calls, math or string expressions and so on as a default values for your function arguments.
Example:
{
echo "Name = $name\n";
echo "Age = $age\n";
}
/* Call without arguments */
test();
/*
You should see: name = PH7 rscd age
= 25 */
/*
Call with a single argument */
test('Me'); /* You should see: name = Me age = 25 */
The $name parameter takes as it's default value a complex expression which is the concatenation of the string 'PH7' and a random string of length 4 bytes generated by the built-in rand_str() function. The default value for the $age parameter is a constant math expression. If you run this example using the standard PHP engine, you will get a fatal error while under PH7 this example would run perfectly.
PH7 goes further and let you even use anonymous functions as a default value for your function arguments.
Example:
{
/* Check if we are dealing with a callback */
if( !is_callable($callback) ){
die("Expecting a callback");
}
/* Invoke the callback */
$callback();
}
/* Call without arguments */
test(); /* You should see: Hello World */
/* Call with a single argument */
test(function(){ echo "Welcome guest";}); /* You should see: Welcome guest */
That is, the $callback parameter takes as it's default value an anonymous function that echo “hello world” . This anonymous function will be invoked when the user calls the test() function without arguments.
UTF-8 Variables and Function names
PH7 has native support for UTF-8. That is, you are not restricted to use plain-English to name your variables or functions. Any UTF-8 encoded natural language (i.e: Japanese, Chinese, Arabic, etc.) can do the job.
Example:
$文書 = "http://ph7.symisc.net";
function ダウンロード(){
echo "http://ph7.symisc.net/downloads.html";
}
/* Test */
var_dump($概要,$文書);
/* Call the download function */
ダウンロード();
As you can see, there is no need for ICU or any other internationalization packages, all you need to do is write you PHP variables and function names in your natural language.
Complex expressions for static variables and constant
Again, PH7 goes further and let you use any complex expressions including function calls as an initialization values for your static variables and constants.
Example:
{
/* Random number between 0 and 1023 as the initialization value for the static variable */
static $salt = rand() & 0x3FF;
/* Echo the random number and increment it's value by 1*/
echo $salt++.PHP_EOL;
}
/* Random string of length 6 for our test constant */
const MY_CONST = rand_str(6);
/* Test */
test(); /* You should see a random number between 0 and 1023 [ex: 596 ] */
test(); /* 597 */
test(); /* 598 */
echo "MY_CONST value = ",MY_CONST,PHP_EOL;
Here, the static variable $salt takes as its initialization value a random number between 0 and 1023 inclusive generated by the built-in rand() function while the constant MY_CONST takes at its initialization value a random string generated by the built-in rand_str() function. Also note that the 'const' construct can be used outside a class definition.
Anonymous functions extensions
PH7 implements anonymous functions as well closures and introduces some amazing extensions to these constructs such as:
Anonymous function arguments can take a default value exactly like standard function arguments. The default value associated with the function argument can be any complex expression including function calls.
Example:
echo $msg.PHP_EOL;
}; //Don't forget the semi-colon here
/* Call the anonymous function without arguments */
$anon(); //You should see 'Hello World!'
/* Now,call the anonymous function with a simple argument */
$anon('Welcome guest'); //You should see 'Welcome guest'
Now the operators precedence table have been improved dramatically, anonymous functions can be invoked on the fly without any kind of assignment, simply delimit the anonymous function declaration in parenthesis and use the call operator '()' to perform the invocation.
Example: On the fly call of an anonymous function
(function(){echo 'Hello World!'.PHP_EOL;})(); //You should see 'Hello Wold!'
/* On the fly call, with arguments*/
(function(string $msg){echo $msg.PHP_EOL;})('Welcome Guest'); //You should see 'Welcome Guest!';
The previous code fragment is equivalent to this old style code
$anon(); //You should see 'Hello Wold!';
Anonymous function can embed static variables exactly the same way a standard PHP function does.
No Fatal Errors
Under PH7, the concept of run-time error is ignored and PH7 will try everything possible to let your program continue it's execution normally. A run-time error is an error that occurs while executing your program. Same example of run-time error includes a call to an undefined function or a instantiation of an undefined class. In both scenario PH7 will throw a simple warning and assume a null return value.
Suppose you have called an undefined function (PH7 does not implements all PHP functions such as crypt() ereg_replace() and so on). Rather than aborting program execution and following the standard PHP engine behavior, PH7 will set a null return value instead so that your program can continue its execution normally giving the illusion that the undefined function have been called and returned null.
Example: (Call an undefined function)
$a = undefined_function(1,2,3);
var_dump($a); /* NULL */
echo "I'm not dead at: ",__DATE__,' ',__TIME__; //Output: I'm not dead at 2012-05-10 23:05:59
Here, $a have been assigned the null value since the undefined_function does not exists and thus cannot be called. The program continue its execution normally, dumping $a and outputting a message.
Example 2: (Call to an undefined class)
$a = new Undefined_Class();
var_dump($a); /* NULL */
echo "I'm not dead at: ",__DATE__,' ',__TIME__; //Output: I'm not dead at 2012-05-10 00:27:17
Here, we have tried to instantiate an undefined class. PH7 will throw a warning and return NULL instead so that the program can continue its execution normally.
The same rule apply, if you access an undefined array entry (I.e: $arr['undefined_index']) or an undefined class attribute (I.e: $class->undefined_attr). In each cases, PH7 throw a warning and return NULL instead.
The only fatal run-time error under PH7 that really could stop program execution is an out of memory. Fortunately PH7 have a tiny memory footprint (depending of course on the executed program an it's proper memory usage) and running out of memory on modern hardware even on modern embedded devices is an extremely rare scenario and we can say that your program is pretty safe.
Remember not to confuse run-time errors with compile-time error that occurs while compiling your PHP script using one of the compile interfaces. These compile-time errors are generally due to malformed PHP programs (that you must fix manually after viewing the compile error log) while run-time errors occurs during execution of the compiled program.
Single statement without parenthesis
Standard PHP functions (not anonymous) can omit the curly braces if their body comprise only a single statement (This behavior is identical to the if statement).
Example:
echo 'Hello World!'.PHP_EOL; // single statement
//Invoke the previous function
test(); //You should see 'Hello Wold!'
Example 2:
if( $arg )
echo "Boolean TRUE\n";
else
echo "Boolean FALSE\n";
//Invoke with a boolean truetest(TRUE); // You should see 'Boolean TRUE'
Arrays are always passed by reference
PH7 pass and return arrays by reference exactly the same way PHP(5) pass objects (class instances) by reference. That is, when assigning an already created instance of an array to a new variable, the new variable will access the same instance as the array that was assigned. This behavior is the same when passing instances to a function. A copy of an already created array can be made by calling the built-in array_copy($src); function. an array variable doesn't contain the array itself as value anymore. It only contains an array identifier which allows array accessors to find the actual array. When an array is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier which points to the same array. If you came from C/C++ thinks of this as two variables pointing to the same instance of a malloc'ed structure.
Example: Array assignments
$b = $a; /* After this assignment, the two variables point to the same array instance */
/* Remove the middle entry using variable $b */
unset($b[1] /* 50 */);
/* Dump using variable $a */
var_dump($a); /* Output: array 2( 0 => 'sample' , 2 => 'value' ); */
/* Check if the two variable point to the same instance */
var_dump( $a == $b ); /* bool(TRUE) */
Here, variable $a and $b point to the same array instance, so if you remove one entry using variable $a, the change is immediately seen in variable $b if you dump it. In other words, $a and $b point to the same instance.
Example 2: Passing array to function
{
/* Remove the last array entry */
array_pop($arg);
}
$a = array('sample',50,'value'); /* Create a new array instance */
/* Call the pop() function */
pop($a);
/* Dump $a */
var_dump($a); /* Output: array 2( 0 => 'sample' , 1 => '50' )*/
Here, even without including the reference operator & to the function argument, the array is passed by reference and the change is immediately seen (the pop operation) in variable $a.
To mimic the standard PHP engine behavior and to get a private copy of a array for each variable, you can use the array_copy() function as follows:
/* Let $b have a private copy of the array instance assigned to $a */
$b = array_copy($a);
/* Now $a and $b point to a completely different instances */
array_pop($a);
var_dump($a); //Output array 2(0 => 'sample' , 1 => 50 );
/* Dump $b */
var_dump($b); //Output array 3(0 => 'sample' , 1 => 50 , 2 => 'value');
After calling array_copy(), $a and $b points to completely different instances. This is the solution if you want to pass and/or assign arrays by copy, but remember for performance reason it's recommended that you let PH7 pass array by reference and thus you avoid a heavy copy operation.
Hand-coded Project
The reason why performance rocks under PH7 relies in the fact that is a hand-coded project. That is, PH7 does not use any external tools to generate it's lexical analyzer such as lex or flex nor does not use LALR(1) parsers such as lemon, Bison or YACC to generate it's parser, everything is hand-coded by the Symisc Development Team. By acting so, the lexer and the parser are now thread-safe, full re-entrant, generate better error message, takes less space (100 KB together) in the source tree and are easy to maintain.
PH7 is a compact library. With all features enabled, the library size can be less than 600KiB, depending on compiler optimization settings. (Some compiler optimizations such as aggressive function inlining and loop unrolling can cause the object code to be much larger.) If optional features are omitted, the size of the PH7 library can be reduced below 220KiB. PH7 can also be made to run in very little heap (2MB), making PH7 a popular PHP engine choice on memory constrained gadgets such as cellphones ,tablets, numeric devices and so on.
PH7 is written in ANSI C, compile and run unmodified in any platform including restricted embedded device with a C compiler. PH7 have been extensively tested under Windows and UNIX including Linux (and its' flavours), FreeBSD (main development platform with Windows 7), Oracle Solaris and Mac OS X.
If you have successfully compiled and tested PH7 in an exotic environment or a proprietary UNIX such as HP-UX or AIX, please post a report in the PH7 forums or send an email to devel@symisc.net.
Amalgamation
PH7 source tree includes a little script written in PHP that is responsible of building an object called the "amalgamation" after successful compilation of the PH7 project. The amalgamation (Concept introduced by the SQLite project) is a single C code file, named "ph7.c", that contains all C code for the core PH7 library and it's extensions. This file contains about 61K lines of code and is over 1.9 megabytes in size.
The amalgamation contains everything you need to integrate PH7 into a larger project. Just copy the amalgamation into your source directory and compile it along with the other C code files in your project. You may also want to make use of the "ph7.h" header file that defines the programming API for PH7. The ph7.h header file is available separately. The ph7.h file is also contained within the amalgamation, in the first couple of thousand lines. So if you have a copy of ph7.c but cannot seem to locate ph7.h, you can always regenerate the ph7.h by copying and pasting from the amalgamation.
In addition to making PH7 easier to incorporate into other projects, the amalgamation also makes it run faster. Many compilers are able to do additional optimizations on code when it is contained with in a single translation unit such as it is in the amalgamation.
The amalgamation and the ph7.h header file are available on the download page as a file named ph7-amalgamation-X_X_X.zip where the X's are replaced by the appropriate version number.
Built-in HTTP Request Parser
PH7 includes a powerful HTTP request parser with the ability to extract MIME headers, decode GET/POST raw queries and populate the appropriate arrays such as $_GET, $_POST, $_SERVER and so on. This feature is popular for network oriented application such as web servers that embed the PH7 engine and need to pass HTTP informations to their PHP scripts. Refer to the PH7_VM_CONFIG_HTTP_REQUEST configuration option for additional information.
Hash-maps to represent arrays
PH7 uses the hashmap data structure internally to represent the array type. A hashmap is is a data structure that uses a hash function to map identifying values, known as keys, to their associated values. The hashmap implementation is written from scratch by the Symisc Development Team and uses two distinct (Inter-changeable) hash functions for it's operation. The first hash function is used to map 64-bit integer keys (Automatic indexes) to their bucket address in the table while the second hash function (DJB based implementation) is used for string keys. The hasmap implementation is found in the hashmap.c source file from the PH7 source tree.
Built-in sorting functions such as sort(), usort(), ksort(), rsort() and so on uses an efficient implementation of the stable merge-sort algorithm. The PH7 merge-sort implementation is based on the one found in the SQLite source tree.
Language construct in the context of a function call
You can now use language constructs such as echo, include, print and so on in the context of a function call as follows:
$my_echo("Hello World\n"); //Output Hello World
//or
fopen("Sample.txt") or echo "IO error while opening file";
You can store constructs names in a array and perform a call by dereferencing the array directly as follows:
//Call the print function on the fly
$lang_constrcut[1 /* print index*/]("Hello World\n"); //Outputs: Hello World
//Include a dummy file on the fly
$lang_constrcut[2]('dummy_file'); //Output: IO error while importing dummy_file
Thanks to the improved operators precedence table for letting us introduce this smart extension.
Floating Point Comparison
The standard PHP engine is reputed for his inconsistency while playing with floating point numbers. Under PH7, you can work and compare floating point numbers exactly the same way you work with integers without any unexpected or inconsistent result.
Example:
var_dump(0.41 == 1.4); //bool(FALSE)
var_dump(15.00 == 15 ); //bool(TRUE)
Correct implementation of the ternary operator
Unlike the standard PHP engine, the ternary operator under PH7 now evaluates left-to-right, associates right-to-left. That is, there is no need for parenthesis for nested ternary operators.
Example:
echo
true
?
'true'
:
false
?
't'
:
'f'
;
The following PHP expression will output 't' when running using the standard PHP engine and is an unexpected result, but if your run this code using the PH7 engine this will output 'true' as you might expect.
Another example (using concatenation) to test right to left associativity:
This will output 'FALSE [bad ternary]' when running using the standard PHP engine but outputs 'TRUE [good ternary]' when running using the PH7 engine.
Array cursor is automatically reset.
The array cursor is automatically reset to the beginning at the end of a running foreach() loop. That is, there in no need to manually call the built-in reset() function to reset the array cursor, this operation is done automatically.
const/var statements outside class definition
The const construct can be used now to declare constants outside a class definition. Note that as an extension, constants initialization values can be any complex expression including function calls as follows:
// set to the the string 'PH7' with a random generated string of length 6
const MY_CONST = 'PH7 '.rand_str(6);
//Expand the constant
echo MY_CONST ; //You should see something like 'PH7 dxthob'
Similarly, the var construct which is used to declare public class attributes can be used now to declare variables outside a class definition.
call_user_func() support pass by reference
As of this release, you can pass argument by reference as by copy to the built-in call_user_func() function, this smart extension allow the called function to modify the contents of the passed variable like a standard PHP function would do.
Example:
{
$var += 10;
}
$a = 25;
call_user_func('add', $a);
echo $a."\n"; //You should see 35 now,since $a was passed by reference to the add() function
Caveats
While PH7 implements most of the PHP(5.3) constructs, they are some constructs and behavior that was omitted or cannot be implemented due to the embedded nature of the engine. Some of them are:
namespace implementation was dropped from the build. In fact Symisc (the developer of the PH7 engine) have an early prototype of PH7 with namespace support but we found that this construct have no particular sense in restricted environments since PH7 tend to be embedded in host application that generally deal with small to medium size PHP scripts. But if you want this features, let us know!.
The declare constrcut is simply a no-op operation in the current release of the PH7 engine. In fact the Symisc development team did not understand the purpose of this constrcut. If you really know its purpose please post a message in the PH7 public forums.
Traits are not implemented as of this version (2.1.4) and will be available in the next release of the PH7 engine.
The serialize() and unserialize() functions are a simple wrapper around the built-in function json_encode() and json_decode().
The list() construct support only one nesting level (No nested list()).
PH7 lack more or less some important functions such preg_replace(), preg_match(), mysql_connect() and so on. Refer to the following page for the list of built-in PHP functions. The Symisc Development team is working very hard to overcome this limit and you are invited to contribute and join the PH7 development process (Read this for more information).
Built-in array_splice() does not support insertions.
And finally, we recommended the PH7 users to report any unexpected result or inconsistencies using the online bug tracker.
Any feedback (We want to hear from you), please send an email to devel@symisc.net.
