Almost everybody use standard PHP runtime. So many assume there is only one PHP runtime. But actually there are alternative runtimes.
Here we will look at some of the alternative runtimes and how to use them and how compatible they are.
hello.php:
<html>
<head>
<title>Hello world</title>
</head>
<body>
<?php
echo "<p>PHP says: Hello world!</p>\r\n";
?>
</body>
</html>
basic.php:
<html>
<head>
<title>Basic stuff</title>
</head>
<body>
<?php
$rep = 3;
$s = 'ABC';
$res = '';
for($i = 0; $i < $rep; $i++) {
if(strlen($res) > 0) {
$res .= ' ';
}
$res .= $s;
}
echo "<p>$rep * '$s' = '$res'</p>\r\n";
?>
</body>
</html>
func.php:
<html>
<head>
<title>Functions</title>
</head>
<body>
<?php
function fac($n) {
if($n < 2) {
return 1;
} else {
return $n * fac($n - 1);
}
}
$fac5 = fac(5);
echo "<p>5! = $fac5\r\n";
?>
</body>
</html>
form.php:
<html>
<head>
<title>Form</title>
</head>
<body>
<form method='POST'>
F1 : <input name='f1' type='TEXT'>
<br>
F2 : <input name='f2' type='TEXT'>
<br>
<input type='SUBMIT' value='Submit'>
</form>
<?php
if($_SERVER['REQUEST_METHOD'] == 'POST') {
$f1 = $_POST['f1'];
$f2 = $_POST['f2'];
echo "<p>$f1 $f2</p>\r\n";
}
?>
</body>
</html>
oop.php:
<html>
<head>
<title>OOP</title>
</head>
<body>
<?php
abstract class P {
public abstract function getId();
public function printId() {
$id = $this->getId();
echo "<p>Instance says: I am $id</p>\r\n";
}
}
class C1 extends P {
public function getId() {
return 'C1';
}
}
class C2 extends P {
public function getId() {
return 'C2';
}
}
$o1 = new C1();
$o1->printId();
$o2 = new C2();
$o2->printId();
?>
</body>
</html>
mysqli.php:
<html>
<head>
<title>mysqli extension</title>
</head>
<body>
<?php
$con = new mysqli('localhost', 'root', '', 'Test');
if(mysqli_connect_errno()) die(mysqli_connect_error());
$stmt = $con->prepare('SELECT f1,f2 FROM T1 WHERE f1 BETWEEN ? AND ?') or die(mysqli_error($con));
$start = 2;
$end = 4;
$stmt->bind_param('ii', $start, $end);
$stmt->execute() or die(mysqli_error($con));
$rs = $stmt->get_result();
echo "<table border='1'>\r\n";
echo "<tr>\r\n";
echo "<th>F1</th>\r\n";
echo "<th>F2</th>\r\n";
echo "</tr>\r\n";
while($row = $rs->fetch_array(MYSQLI_ASSOC)) {
$f1 = $row['f1'];
$f2 = $row['f2'];
echo "<tr>\r\n";
echo "<td>$f1</td>\r\n";
echo "<td>$f2</td>\r\n";
echo "</tr>\r\n";
}
echo "</table>\r\n";
$stmt->close();
$con->close();
?>
</body>
</html>
For more about mysqli extension see PHP Database Access.
pdo.php:
<html>
<head>
<title>PDO extension (for MySQL)</title>
</head>
<body>
<?php
$con = new PDO('mysql:host=localhost;dbname=Test', 'root', '');
$con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$stmt = $con->prepare('SELECT f1,f2 FROM T1 WHERE f1 BETWEEN :start AND :end');
$start = 2;
$end = 4;
$stmt->execute(array(':start' => $start, ':end' => $end));
echo "<table border='1'>\r\n";
echo "<tr>\r\n";
echo "<th>F1</th>\r\n";
echo "<th>F2</th>\r\n";
echo "</tr>\r\n";
while($row = $stmt->fetch()) {
$f1 = $row['f1'];
$f2 = $row['f2'];
echo "<tr>\r\n";
echo "<td>$f1</td>\r\n";
echo "<td>$f2</td>\r\n";
echo "</tr>\r\n";
}
echo "</table>\r\n";
?>
</body>
</html>
For more about PDO extension see PHP Database Access.
json.php:
<body>
<?php
$a = array('f1' => 99, 'f2' => 'XXX');
$json = json_encode($a);
echo "<p>JSON = $json<p>\r\n";
$o = json_decode($json);
$f1 = $o->f1;
$f2 = $o->f2;
echo "<p>$f1 $f2</p>\r\n";
?>
</body>
</html>
For more about JSON usage in PHP see JSON Processing.
cpu.php:
<html>
<head>
<title>JSON</title>
</head>
<html>
<head>
<title>CPU usage</title>
</head>
<body>
<?php
define('REP', 10);
define('M', 10);
define('N', 1000000);
function testint() {
$t1 = microtime(true);
for($i = 0; $i < M; $i++) {
$sum = $i;
for($j = 0; $j < N; $j++) {
$sum = (int)((($sum + 1) * 2 + 1) / 2);
}
if($sum != ($i + N)) {
die('Error');
}
}
$t2 = microtime(true);
echo sprintf("<p>%.3f seconds\n", $t2 - $t1);
}
for($i = 0; $i < REP; $i++) {
testint();
}
?>
</body>
</html>
All the code is very simple, but if this code works then a lot of PHP code will work.
Standard PHP is what you either get from the operating system distribution or download and install from PHP.NET.
When people talk about PHP then this is what they mean.
It is sometimes called Zend PHP because it since version 4.0 has been using the socalled Zend Engine.
Current versions are 7.x and 8.x. Versions 5.x (and obviously earlier) are obsolete. Note that there were no version 6.x.
It is bascially a PHP interpreter written in C.
It can be used in many diffent ways.
A not widely known fact is that PHP can be run standalone.
Simply:
php -S localhost:8000
Note that standalone server is not intended for production usage - it is only intended for development usage.
PHP integrates nicely with Apache. Running PHP via Apache is undoubetly the most common way to run PHP.
PHP comes with an Apache module, so integration basically mean modifying Apache config to load the PHP Apache module and associate it with the the .php file extension.
PHP also comes with integration modules for Microsoft IIS, nginx and LightHTTPD. Plus PHP supports CGI and FastCGI so any web server supporting those can integrate with PHP.
Test | Result |
---|---|
Hello world | OK |
Basic stuff | OK |
Functions | OK |
Form | OK |
OOP | OK |
mysqli extension | OK |
PDO extension (for MySQL) | OK |
JSON | OK |
CPU usage | 5.6 (32 bit) : 1.24s 7.2 (32 bit) : 1.19s 7.4 (32 bit) : 1.29s 7.4 (64 bit) : 1.17s |
No surprise that everything works in the standard implementation.
Hip Hip is a series of PHP implementations from FaceBook.
HPHPc (HipHop for PHP) from 2010 was a transpiler from PHP to C++.
In 2013 it was replaced by HHVM (HipHop VM) a VM that JIT compiles and execute PHP code.
Version 1 to 3 supported both PHP and Hack. Version 4+ only supports Hack.
(Hack is an extension of PHP allowing for more type safe code)
Latest HHVM (4.x) can usually be installed on Linux using normal package manager.
Getting HHVM 3.x installed on Linux require installing dependencies, download source code and building. Definitely doable but it takes some time.
(to run PHP code one needs HHVM 3.x)
To run HHVM use:
hhvm -m server -p 8000
Test | Result |
---|---|
Hello world | OK |
Basic stuff | OK |
Functions | OK |
Form | OK |
OOP | OK |
mysqli extension | Fail |
PDO extension (for MySQL) | OK |
JSON | OK |
CPU usage | 1.93 s |
Hack is really just PHP 7 as FaceBook thougth it should have been, so migrating from PHP to hack is not difficult.
hello.hack:
<<__EntryPoint>>
function main(): void {
echo <<< EOS
<html>
<head>
<title>Hello world</title>
</head>
<body>
EOS;
echo "<p>PHP says: Hello world!</p>\r\n";
echo <<< EOS
</body>
</html>
EOS;
}
basic.hack:
<<__EntryPoint>>
function main(): void {
echo <<< EOS
<html>
<head>
<title>Basic stuff</title>
</head>
<body>
EOS;
$rep = 3;
$s = 'ABC';
$res = '';
for($i = 0; $i < $rep; $i++) {
if(strlen($res) > 0) {
$res .= ' ';
}
$res .= $s;
}
echo "<p>$rep * '$s' = '$res'</p>\r\n";
echo <<< EOS
</body>
</html>
EOS;
}
func.hack:
function fac($n) {
if($n < 2) {
return 1;
} else {
return $n * fac($n - 1);
}
}
<<__EntryPoint>>
function main(): void {
echo <<< EOS
<html>
<head>
<title>Functions</title>
</head>
<body>
EOS;
$fac5 = fac(5);
echo "<p>5! = $fac5\r\n";
echo <<< EOS
</body>
</html>
EOS;
}
form.hack:
<<__EntryPoint>>
function main(): void {
echo <<< EOS
<html>
<head>
<title>Form</title>
</head>
<body>
<form method='POST'>
F1 : <input name='f1' type='TEXT'>
<br>
F2 : <input name='f2' type='TEXT'>
<br>
<input type='SUBMIT' value='Submit'>
</form>
EOS;
if($_SERVER['REQUEST_METHOD'] == 'POST') {
$f1 = $_POST['f1'];
$f2 = $_POST['f2'];
echo "<p>$f1 $f2</p>\r\n";
}
echo <<< EOS
</body>
</html>
EOS;
}
oop.hack:
abstract class P {
public abstract function getId();
public function printId() {
$id = $this->getId();
echo "<p>Instance says: I am $id</p>\r\n";
}
}
class C1 extends P {
public function getId() {
return 'C1';
}
}
class C2 extends P {
public function getId() {
return 'C2';
}
}
<<__EntryPoint>>
function main(): void {
echo <<< EOS
<html>
<head>
<title>OOP</title>
</head>
<body>
EOS;
$o1 = new C1();
$o1->printId();
$o2 = new C2();
$o2->printId();
echo <<< EOS
</body>
</html>
EOS;
}
mysqli.hack:
<<__EntryPoint>>
function main(): void {
echo <<< EOS
<html>
<head>
<title>mysqli extension</title>
</head>
<body>
EOS;
$con = new mysqli('192.168.0.140', 'root', 'hemmeligt', 'Test');
if(mysqli_connect_errno()) die(mysqli_connect_error());
$stmt = $con->prepare('SELECT f1,f2 FROM T1 WHERE f1 BETWEEN ? AND ?');
if(!$stmt) die(mysqli_error($con));
$start = 2;
$end = 4;
$stmt->bind_param('ii', $start, $end);
$sts = $stmt->execute();
if(!$sts) die(mysqli_error($con));
$rs = $stmt->get_result();
echo "<table border='1'>\r\n";
echo "<tr>\r\n";
echo "<th>F1</th>\r\n";
echo "<th>F2</th>\r\n";
echo "</tr>\r\n";
while($row = $rs->fetch_array(MYSQLI_ASSOC)) {
$f1 = $row['f1'];
$f2 = $row['f2'];
echo "<tr>\r\n";
echo "<td>$f1</td>\r\n";
echo "<td>$f2</td>\r\n";
echo "</tr>\r\n";
}
echo "</table>\r\n";
$stmt->close();
$con->close();
echo <<< EOS
</body>
</html>
EOS;
}
pdo.hack:
<<__EntryPoint>>
function main(): void {
echo <<< EOS
<html>
<head>
<title>PDO extension (for MySQL)</title>
</head>
<body>
EOS;
$con = new PDO('mysql:host=192.168.0.140;dbname=Test', 'root', 'hemmeligt');
$con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$stmt = $con->prepare('SELECT f1,f2 FROM T1 WHERE f1 BETWEEN :start AND :end');
$start = 2;
$end = 4;
$stmt->execute(dict[':start' => $start, ':end' => $end]);
echo "<table border='1'>\r\n";
echo "<tr>\r\n";
echo "<th>F1</th>\r\n";
echo "<th>F2</th>\r\n";
echo "</tr>\r\n";
while($row = $stmt->fetch()) {
$f1 = $row['f1'];
$f2 = $row['f2'];
echo "<tr>\r\n";
echo "<td>$f1</td>\r\n";
echo "<td>$f2</td>\r\n";
echo "</tr>\r\n";
}
echo "</table>\r\n";
echo <<< EOS
</body>
</html>
EOS;
}
json.hack:
<<__EntryPoint>>
function main(): void {
echo <<< EOS
<html>
<head>
<title>JSON</title>
</head>
<body>
EOS;
$a = dict['f1' => 99, 'f2' => 'XXX'];
$json = json_encode($a);
echo "<p>JSON = $json<p>\r\n";
$o = json_decode($json);
$f1 = $o->f1;
$f2 = $o->f2;
echo "<p>$f1 $f2</p>\r\n";
echo <<< EOS
</body>
</html>
EOS;
}
cpu.hack:
const REP = 10;
const M = 10;
const N = 1000000;
function testint() {
$t1 = microtime(true);
for($i = 0; $i < M; $i++) {
$sum = $i;
for($j = 0; $j < N; $j++) {
$sum = (int)((($sum + 1) * 2 + 1) / 2);
}
if($sum != ($i + N)) {
die('Error');
}
}
$t2 = microtime(true);
echo sprintf("<p>%.3f seconds\n", $t2 - $t1);
}
<<__EntryPoint>>
function main(): void {
echo <<< EOS
<html>
<head>
<title>CPU usage</title>
</head>
<body>
EOS;
for($i = 0; $i < REP; $i++) {
testint();
}
echo <<< EOS
</body>
</html>
EOS;
}
Results:
Test | Result |
---|---|
Hello world | OK |
Basic stuff | OK |
Functions | OK |
Form | OK |
OOP | OK |
mysqli extension | Fail |
PDO extension (for MySQL) | OK |
JSON | OK |
CPU usage | 0.08 s |
It is obvious that HHVM JIT compiler works very well.
Quercus is a PHP implementation for Java servlet engine from Caucho. It has existed since 2007.
There is an open source version (GPL license) and a commercial version.
The open source version interprets PHP. The commercial version compiles PHP.
It seems like the development of quercus is somewhat slowed down.
To use Quercus:
web.xml:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
<servlet>
<servlet-name>Quercus Servlet</servlet-name>
<servlet-class>com.caucho.quercus.servlet.QuercusServlet</servlet-class>
<init-param>
<param-name>license-directory</param-name>
<param-value>WEB-INF/licenses</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Quercus Servlet</servlet-name>
<url-pattern>*.php</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
For more info about how to use Quercus see Java EE tricks.
PHP running via Quercus can use Java code, which may be useful.
Test.java:
package demo;
import java.util.List;
public class Test {
public int add(int a, int b) {
return a + b;
}
public String dup(String s) {
return s + s;
}
public long sum(List lst) {
long res = 0;
for(long v : (List<Long>)lst) res += v;
return res;
}
public String conc(List lst) {
String res = "";
for(String v : (List<String>)lst) res += v;
return res;
}
}
call.php:
<html>
<head>
<title>Calling Java</title>
</head>
<body>
<?php
import demo.Test;
$o = new Test();
$a = 123;
$b = 456;
$c = $o->add($a, $b);
echo "<p>$a + $b = $c</p>\r\n";
$s = "ABC";
$s2 = $o->dup($s);
echo "<p>$s + $s = $s2</p>\r\n";
$a1 = array(1, 2, 3);
$sum1 = $o->sum($a1);
echo "<p>array sum = $sum1</p>\r\n";
$a2 = array('A', 'BB', 'CCC');
$conc2 = $o->conc($a2);
echo "<p>array conc = $conc2</p>\r\n";
?>
</body>
</html>
just add class file to WEB-INF/classes/demo or jar file to WEB-INF/lib.
Test | Result |
---|---|
Hello world | OK |
Basic stuff | OK |
Functions | OK |
Form | OK |
OOP | OK |
mysqli extension | OK |
PDO extension (for MySQL) | OK |
JSON | OK |
CPU usage | 1.48s |
PeachPie is an open source PHP compiler for .NET platform. It has existed since 2016, but is based on a similar open source projects Phalanger that goes back to 2013.
PeachPie targets .NET Core / .NET 5+ while Phalanger targeted .NET Framework 4.
To create PeachPie project:
dotnet new -i "Peachpie.Templates::*"
dotnet new web -lang PHP
HTML and PHP files are put in Website or subdirs under Website.
To build:
dotnet build
Update Server/Server.csproj if needed. For database access add:
<Project Sdk="Microsoft.NET.Sdk.Web">
...
<ItemGroup>
...
<PackageReference Include="Peachpie.Library.MySql" Version="1.0.6" />
<PackageReference Include="Peachpie.Library.PDO" Version="1.0.6" />
<PackageReference Include="Peachpie.Library.PDO.MySql" Version="1.0.6" />
...
</ItemGroup>
...
</Project>
To run:
cd Server
dotnet run
Test | Result |
---|---|
Hello world | OK |
Basic stuff | OK |
Functions | OK |
Form | OK |
OOP | OK |
mysqli extension | Fail |
PDO extension (for MySQL) | OK |
JSON | OK |
CPU usage | 1.63s |
PHP running via PeachPie can use .NET code, which may be useful.
somelib.cs:
using System.Collections;
namespace Demo
{
public interface IHandler
{
void DoIt(int v);
}
public class Test
{
public int Add(int a, int b)
{
return a + b;
}
public string Dup(string s)
{
return s + s;
}
public long Sum(IList lst)
{
long res = 0;
foreach(long v in lst) res += v;
return res;
}
public string Conc(IList lst)
{
string res = "";
foreach(string v in lst) res += v;
return res;
}
public void Process(IHandler h, int v)
{
h.DoIt(v);
}
}
}
call.php:
<html>
<head>
<title>Calling C#</title>
</head>
<body>
<?php
use Demo\IHandler;
use Demo\Test;
class MyHandler implements IHandler {
public function DoIt($v) {
echo "<p>MyHandler.DoIt: $v</p>\r\n";
}
}
$o = new Test();
$a = 123;
$b = 456;
$c = $o->Add($a, $b);
echo "<p>$a + $b = $c</p>\r\n";
$s = "ABC";
$s2 = $o->Dup($s);
echo "<p>$s + $s = $s2</p>\r\n";
$a1 = array(1, 2, 3);
$sum1 = $o->Sum($a1);
echo "<p>array sum = $sum1</p>\r\n";
$a2 = array('A', 'BB', 'CCC');
$conc2 = $o->Conc($a2);
echo "<p>array conc = $conc2</p>\r\n";
$o->Process(new MyHandler(), 123);
?>
</body>
</html>
add a reference to DLL in Server.csproj:
<Project Sdk="Microsoft.NET.Sdk.Web">
...
<ItemGroup>
...
<Reference Include="SomeLib">
<HintPath>..\..\somelib.dll</HintPath>
</Reference>
...
</ItemGroup>
...
</Project>
and modify somelib.csproj to build for the same .NET version as PeachPie (at the time of writing that is netstandard2.1!):
<Project Sdk="Microsoft.NET.Sdk">
...
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
</PropertyGroup>
...
</Project>
Version | Date | Description |
---|---|---|
1.0 | September 9th 2021 | Initial version |
1.1 | September 17th 2021 | Add Hack section and Java/C# interoperability sections |
See list of all articles here
Please send comments to Arne Vajhøj
I will conclude that: