KEMBAR78
Zephir - A Wind of Change for writing PHP extensions | PPTX
Zephir
A WIND OF CHANGE FOR WRITING PHP EXTENSIONS
What is Zephir?
Zephir – Zend Engine PHP Intermediate.
A high-level domain-specific language (DSL) that simplifies
the creation and maintain-ability of native C extensions for
PHP.
Developed by the team behind Phalcon, the PHP CMS
written in C.
What is Zephir?
The creators of Zephir actually pronounce it “zaefire”.
(/ˈzäfī(-ə)r/)
But I still pronounce it “Zephir” (/ˈzef.ər/)
The Zephir Language is an open source project licensed
under an MIT license.
Zephir is written in PHP.
What is Zephir?
In a nutshell
Zephir makes it easy for high-level developers write low-level PHP
Extensions.
Writing a PHP Extension
https://wiki.php.net/internals/references
http://www.phpinternalsbook.com/
http://www.amazon.com/Extending-Embedding-PHP-Sara-Golemon/dp/067232704X
Why might I write an Extension?
Native C Extensions to PHP can typically execute faster than
raw PHP code.
The ability to use native C datatypes in an Extension may
help save memory usage.
Deploying an Extension allows you to keep the source of
your code closed.
Why might I write an Extension?
If a class is heavily IO bound, or requires the allocation/
deallocation of large amounts of memory, then you will
probably not gain any performance benefits.
Unless you can take advantage of the native C datatypes
internally in the code, then you will probably not gain any
memory benefits.
Why might I write an Extension?
Performance comparison
HHVM vs Zephir vs PHP
https://www.simonholywell.com/post/2014/02/hhvm-vs-zephir-vs-php-the-
showdown/
https://www.simonholywell.com/static/files/2014-02-28/index.html
Simon Holywell
Australian Zend certified Development Director at Mosaic in Brighton, UK
What is Zephir?
http://zephir-lang.com/
https://github.com/phalcon/zephir
Zephir – Installation (Ubuntu)
Requirements
◦gcc >= 4.x/clang >= 3.x
◦re2c 0.13 or later
◦gnu make 3.81 or later
◦autoconf 2.31 or later
◦automake 1.14 or later
◦libpcre3
◦php development headers and tools
Zephir – Installation (Ubuntu)
$ sudo apt-get update
$ sudo apt-get install -y python-software-properties
$ sudo apt-get install -y curl
$ sudo apt-get install -y git gcc make re2c libpcre3-dev
$ sudo add-apt-repository ppa:ondrej/php5-5.6
$ sudo apt-get update
$ sudo apt-get install -y php5 dh-make-php php5-dev
$ sudo apt-get install -y php5-curl php5-gd php5-gmp php5-mcrypt 
php5-intl php5-cli
Zephir – Installation (Ubuntu)
$ php –v
PHP 5.6.13-1+deb.sury.org~precise+3 (cli)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies
with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies
$ phpize –v
Configuring for:
PHP Api Version: 20131106
Zend Module Api No: 20131226
Zend Extension Api No: 220131226
Zephir – Installation (Ubuntu)
$ git clone https://github.com/phalcon/zephir
$ cd zephir
$ ./install-json
$ ./install -c
$ cd ..
$ zephir version
0.8.0a
Zephir – Important Commands
$ zephir init [namespace]
Initialises a Zephir extension
$ zephir compile
Compiles a Zephir extension
$ zephir fullclean
Cleans the object files generated in compilation
$ zephir install
Installs the extension (requires root access)
$ zephir help
Displays help
Zephir – First Steps
$ zephir init helloworld
$ ls helloworld
helloworld/
ext/
helloworld/ ## Our zephir .zep files go here
config.json ## Configuration file for our extension
Zephir – First Steps
$ cd helloworld
$ cat config.json
…
"namespace": "helloworld",
"name": "helloworld",
"description": "Hello World Extension",
"author": "Mark Baker",
"version": "0.0.1",
"verbose": false,
"requires": {
"extensions": []
}
Zephir – First Steps
Organise your code into files and namespaces
Uses Case-Sensitive file/folder names
Always use lower-case for file/folder names
Every file must contain one (and only one) class
Only OOP Code, no new PHP functions
Class names can be mixed-case
Classes must be namespaced
Top-level Namespace should match the namespace defined in config.json
but may be mixed-case
Zephir – First Steps
$ cd helloworld
$ cat greetings.zep
namespace HelloWorld;
class greetings {
public function english() {
// Variables must be defined before they can be used
var greeting;
// "let" is used to assign values to a variable
let greeting = "Hello World";
echo greeting, PHP_EOL;
}
}
Zephir – First Steps
$ cd ..
$ zephir compile
helloworld/
ext/
/helloworld ## zephir generates C source code here
/modules ## zephir builds the PHP Extension here
helloworld/
compile-errors.log
compile.log
config.json
Zephir – First Steps
$ zephir install
or
$ sudo cp ext/modules/helloworld.so /usr/lib/php5/20131226/helloworld.so
$ sudo nano /etc/php5/cli/php.ini
extension=helloworld.so
php -m
Zephir – First Steps
$ php -i | grep -m 2 -A 4 helloworld
helloworld
Hello World Extension
helloworld => enabled
Author => Mark Baker
Version => 0.0.1
Build Date => Sep 27 2015 08:57:19
Powered by Zephir => Version 0.8.0a
Zephir – First Steps
$ cat helloworld.php
<?php
$instance = new HelloWorldgreetings();
$instance->english();
$ php helloworld.php
Hello World
Zephir – Variables
Variable names don’t begin with a $
Variables must be pre-defined/declared
var stringVar = "hello", boolVar = true, intVar = 1.0;
int answer = 42, question = 1;
PHP scope rules apply
Global variables don’t exist in Zephir (except that SuperGlobals can be accessed)
let requestMethod = _SERVER["REQUEST_METHOD"];
Zephir – Variables
Variable variables do not exist in Zephir
But they can be “simulated”
//Set variable $name in PHP
let {"name"} = "hello";
//Set variable $price in PHP
let name = "price";
let {name} = 10.2;
Zephir – Variable Types
Dynamic Typed Variables
Like PHP variables, and can change datatype between the different variable
types supported by PHP
Declared with the keyword “var”
var name = "Mark";
Static Typed Variables
A subset of C-Datatypes
boolean, int, uint, char, uchar, long, ulong, string, array
Can’t change datatype once declared
Declared with the appropriate datatype name
uint counter = 1;
Zephir – Strings
String literals (dynamic var, static string) must be wrapped in double quotes
var name = "Mark Baker";
Character literals (static char, static uchar) must be wrapped in single quotes
char initial = 'M';
Strings in Zephir do not support variable interpolation/parsing; use
concatenation instead:
let forename = "Mark";
let surname = "Baker";
let fullName = forename . " " . surname;
Zephir – Arrays
Array variables can be declared using the keywords “var” or “array”:
var a = []; // dynamic variable
array b = []; // static array variable
As in PHP, keys can only be string or integer values
Syntax is slightly different:
let elements = [
"foo": "bar", // Use of : rather than =>
"bar": "foo" // No trailing , permitted
];
Zephir – Control Structures
public function compare(a, b) {
if a < b {
return -1;
} elseif a > b {
return 1;
}
return 0;
}
Brackets around the evaluated condition are optional
Zephir – Control Structures
let counter = 0;
while counter < 10 {
echo counter, PHP_EOL;
let counter += 1;
}
Brackets around the evaluated condition are optional
Zephir – Control Structures
let n = 10;
loop {
let n -= 2;
if n == 0 { break; }
echo n, PHP_EOL;
}
Zephir – Control Structures
let items = ["a": 1, "b": 2, "c": 3, "d": 4];
for key, value in items {
echo key, " : ", value, PHP_EOL;
}
for key, value in reverse items {
echo key, " : ", value, PHP_EOL;
}
Zephir – Control Structures
string fullName = "Mark Baker"; char character;
for character in fullName {
echo character , PHP_EOL;
}
for character in reverse fullName {
echo character , PHP_EOL;
}
Zephir – Control Structures
let items = ["a": 1, "b": 2, "c": 3, "d": 4];
for key, _ in items {
echo key, PHP_EOL;
}
The value element in the for loop doesn’t need to be declared
Zephir – Exceptions
try {
// exceptions can be thrown here
if (firstCase) {
throw new RuntimeException("This is an exception");
} else {
throw "Untyped Exception";
}
} catch RuntimeException|Exception, e {
// handle exception
echo e->getMessage();
}
Special Features of Zephir
Type Hints
Object/Interface Type Hints
public function injectFilter(<AppFilterInterface> filter)
{
//...
}
Similar to the existing type hints in PHP, although notice the syntax
differences
Special Features of Zephir
Type Hints
“Scalar” Type Hints
public function filterText(string text, boolean escape=false)
{
//...
}
Allows “compatible” types, e.g.
this->filterText(1234, 0);
Will try to convert the data passed to the type-hinted datatype
Special Features of Zephir
Type Hints
Strict Scalar Hints
public function filterText(string! text, boolean escape=false)
{
//...
}
this->filterText(1234, 0);
Will throw an Exception
Special Features of Zephir
Return Type Hints
public function getClassFromFactory() -> <AppMyInterface> {
//...
}
Similar to the return type hints introduced in PHP 7, although notice the
syntax differences
function isValidStatusCode(int $statusCode): bool {
//...
}
Special Features of Zephir
Read-Only Arguments
public function filterText(const string text, boolean escape=false)
{
//...
}
Used for compiler optimisations
Special Features of Zephir
Named Arguments
public function crop(width = 600, height = 400) {
//...
}
this->crop(height: 200);
this->crop(height: 300, width: 400);
Adds a slight performance overhead
Zephir – Pitfalls
Silent compilation failures
$ zephir compile
helloworld/
ext/
/helloworld ## zephir generates C source code here
/modules ## zephir builds the PHP Extension here
helloworld/
compile-errors.log ## Always check this file
compile.log
config.json
Zephir – Pitfalls
Unsupported Features of PHP
Array Dereferencing
Callbacks can’t use “use”
Zephir – Pitfalls
Bad assumptions from lazy PHP practises
In PHP, a pass-by-reference variable in an expression like
$validComplex = preg_match('/^...$/ui', $complexNumber, $complexParts);
will automatically created $complexParts if it doesn't exist;
but Zephir won't do this, so you need to explicitly create it in advance
var complexParts;
let validComplex = preg_match("/^....$/ui", complexNumber, complexParts);
Zephir – Pitfalls
Overly-Complex or Ambiguous Syntax
An expression like
if (!is_object($complex) || !$complex instanceof Complex) { … }
Might logically be translated to Zephir as
if !is_object(complex) || !complex instanceof Complex { … }
but Zephir has a different precedence to PHP for instanceof, so you
need to do
if !is_object(complex) || !(complex instanceof Complex) { … }
otherwise it executes !complex and then tests the result of that (always
a boolean) for instanceOf Complex
cf. https://github.com/phalcon/zephir/issues/277
Zephir – Utilities and Helpers
PHP to Zephir
https://github.com/fezfez/php-to-zephir
Zephir – Utilities and Helpers
$ zephir init helloworld
$ cd helloworld
$ /home/vagrant/vendor/bin/php-to-zephir phpToZephir:convertDir 
<path to PHP source code>
Zephir – Testing
Zephir – Testing
$ cd helloworld
helloworld/
ext/
/helloworld
/modules
run-tests.php ## PHP Test execution script
helloworld/
compile-errors.log
compile.log
config.json
Zephir – Testing
$ cd ext/modules
$ php run-tests.php *.phpt <directory with test files>
$ php run-tests.php --help
Useful Option
-c <filename> ## Custom php.ini file to be used
Zephir – Testing
$ cat helloWorldTest001.phpt
--TEST--
Test Hello World display using helloworld extension
--FILE--
<?php
$instance = new HelloWorldgreetings();
$instance->english();
--EXPECT--
Hello World
Zephir – Testing
$ php run-tests.php *.phpt <directory with test files>
…
=====================================================================
Running selected tests.
PASS Test Hello World display using helloworld extension
[/srv/phpnw2015/helloworld/tests/helloWorldTest-001.phpt]
=====================================================================
Number of tests : 1 1
Tests skipped : 0 ( 0.0%) --------
Tests warned : 0 ( 0.0%) ( 0.0%)
Tests failed : 0 ( 0.0%) ( 0.0%)
Expected fail : 0 ( 0.0%) ( 0.0%)
Tests passed : 1 (100.0%) (100.0%)
---------------------------------------------------------------------
Time taken : 0 seconds
=====================================================================
Zephir – Testing
https://qa.php.net/write-test.php
https://qa.php.net/phpt_details.php
Useful Zephir Links
Zephir Documentation
http://docs.zephir-lang.com/
Zephir Blog
http://blog.zephir-lang.com/

Zephir - A Wind of Change for writing PHP extensions

  • 1.
    Zephir A WIND OFCHANGE FOR WRITING PHP EXTENSIONS
  • 2.
    What is Zephir? Zephir– Zend Engine PHP Intermediate. A high-level domain-specific language (DSL) that simplifies the creation and maintain-ability of native C extensions for PHP. Developed by the team behind Phalcon, the PHP CMS written in C.
  • 3.
    What is Zephir? Thecreators of Zephir actually pronounce it “zaefire”. (/ˈzäfī(-ə)r/) But I still pronounce it “Zephir” (/ˈzef.ər/) The Zephir Language is an open source project licensed under an MIT license. Zephir is written in PHP.
  • 4.
    What is Zephir? Ina nutshell Zephir makes it easy for high-level developers write low-level PHP Extensions.
  • 5.
    Writing a PHPExtension https://wiki.php.net/internals/references http://www.phpinternalsbook.com/ http://www.amazon.com/Extending-Embedding-PHP-Sara-Golemon/dp/067232704X
  • 6.
    Why might Iwrite an Extension? Native C Extensions to PHP can typically execute faster than raw PHP code. The ability to use native C datatypes in an Extension may help save memory usage. Deploying an Extension allows you to keep the source of your code closed.
  • 7.
    Why might Iwrite an Extension? If a class is heavily IO bound, or requires the allocation/ deallocation of large amounts of memory, then you will probably not gain any performance benefits. Unless you can take advantage of the native C datatypes internally in the code, then you will probably not gain any memory benefits.
  • 8.
    Why might Iwrite an Extension? Performance comparison HHVM vs Zephir vs PHP https://www.simonholywell.com/post/2014/02/hhvm-vs-zephir-vs-php-the- showdown/ https://www.simonholywell.com/static/files/2014-02-28/index.html Simon Holywell Australian Zend certified Development Director at Mosaic in Brighton, UK
  • 9.
  • 10.
    Zephir – Installation(Ubuntu) Requirements ◦gcc >= 4.x/clang >= 3.x ◦re2c 0.13 or later ◦gnu make 3.81 or later ◦autoconf 2.31 or later ◦automake 1.14 or later ◦libpcre3 ◦php development headers and tools
  • 11.
    Zephir – Installation(Ubuntu) $ sudo apt-get update $ sudo apt-get install -y python-software-properties $ sudo apt-get install -y curl $ sudo apt-get install -y git gcc make re2c libpcre3-dev $ sudo add-apt-repository ppa:ondrej/php5-5.6 $ sudo apt-get update $ sudo apt-get install -y php5 dh-make-php php5-dev $ sudo apt-get install -y php5-curl php5-gd php5-gmp php5-mcrypt php5-intl php5-cli
  • 12.
    Zephir – Installation(Ubuntu) $ php –v PHP 5.6.13-1+deb.sury.org~precise+3 (cli) Copyright (c) 1997-2015 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies $ phpize –v Configuring for: PHP Api Version: 20131106 Zend Module Api No: 20131226 Zend Extension Api No: 220131226
  • 13.
    Zephir – Installation(Ubuntu) $ git clone https://github.com/phalcon/zephir $ cd zephir $ ./install-json $ ./install -c $ cd .. $ zephir version 0.8.0a
  • 14.
    Zephir – ImportantCommands $ zephir init [namespace] Initialises a Zephir extension $ zephir compile Compiles a Zephir extension $ zephir fullclean Cleans the object files generated in compilation $ zephir install Installs the extension (requires root access) $ zephir help Displays help
  • 15.
    Zephir – FirstSteps $ zephir init helloworld $ ls helloworld helloworld/ ext/ helloworld/ ## Our zephir .zep files go here config.json ## Configuration file for our extension
  • 16.
    Zephir – FirstSteps $ cd helloworld $ cat config.json … "namespace": "helloworld", "name": "helloworld", "description": "Hello World Extension", "author": "Mark Baker", "version": "0.0.1", "verbose": false, "requires": { "extensions": [] }
  • 17.
    Zephir – FirstSteps Organise your code into files and namespaces Uses Case-Sensitive file/folder names Always use lower-case for file/folder names Every file must contain one (and only one) class Only OOP Code, no new PHP functions Class names can be mixed-case Classes must be namespaced Top-level Namespace should match the namespace defined in config.json but may be mixed-case
  • 18.
    Zephir – FirstSteps $ cd helloworld $ cat greetings.zep namespace HelloWorld; class greetings { public function english() { // Variables must be defined before they can be used var greeting; // "let" is used to assign values to a variable let greeting = "Hello World"; echo greeting, PHP_EOL; } }
  • 19.
    Zephir – FirstSteps $ cd .. $ zephir compile helloworld/ ext/ /helloworld ## zephir generates C source code here /modules ## zephir builds the PHP Extension here helloworld/ compile-errors.log compile.log config.json
  • 20.
    Zephir – FirstSteps $ zephir install or $ sudo cp ext/modules/helloworld.so /usr/lib/php5/20131226/helloworld.so $ sudo nano /etc/php5/cli/php.ini extension=helloworld.so php -m
  • 21.
    Zephir – FirstSteps $ php -i | grep -m 2 -A 4 helloworld helloworld Hello World Extension helloworld => enabled Author => Mark Baker Version => 0.0.1 Build Date => Sep 27 2015 08:57:19 Powered by Zephir => Version 0.8.0a
  • 22.
    Zephir – FirstSteps $ cat helloworld.php <?php $instance = new HelloWorldgreetings(); $instance->english(); $ php helloworld.php Hello World
  • 23.
    Zephir – Variables Variablenames don’t begin with a $ Variables must be pre-defined/declared var stringVar = "hello", boolVar = true, intVar = 1.0; int answer = 42, question = 1; PHP scope rules apply Global variables don’t exist in Zephir (except that SuperGlobals can be accessed) let requestMethod = _SERVER["REQUEST_METHOD"];
  • 24.
    Zephir – Variables Variablevariables do not exist in Zephir But they can be “simulated” //Set variable $name in PHP let {"name"} = "hello"; //Set variable $price in PHP let name = "price"; let {name} = 10.2;
  • 25.
    Zephir – VariableTypes Dynamic Typed Variables Like PHP variables, and can change datatype between the different variable types supported by PHP Declared with the keyword “var” var name = "Mark"; Static Typed Variables A subset of C-Datatypes boolean, int, uint, char, uchar, long, ulong, string, array Can’t change datatype once declared Declared with the appropriate datatype name uint counter = 1;
  • 26.
    Zephir – Strings Stringliterals (dynamic var, static string) must be wrapped in double quotes var name = "Mark Baker"; Character literals (static char, static uchar) must be wrapped in single quotes char initial = 'M'; Strings in Zephir do not support variable interpolation/parsing; use concatenation instead: let forename = "Mark"; let surname = "Baker"; let fullName = forename . " " . surname;
  • 27.
    Zephir – Arrays Arrayvariables can be declared using the keywords “var” or “array”: var a = []; // dynamic variable array b = []; // static array variable As in PHP, keys can only be string or integer values Syntax is slightly different: let elements = [ "foo": "bar", // Use of : rather than => "bar": "foo" // No trailing , permitted ];
  • 28.
    Zephir – ControlStructures public function compare(a, b) { if a < b { return -1; } elseif a > b { return 1; } return 0; } Brackets around the evaluated condition are optional
  • 29.
    Zephir – ControlStructures let counter = 0; while counter < 10 { echo counter, PHP_EOL; let counter += 1; } Brackets around the evaluated condition are optional
  • 30.
    Zephir – ControlStructures let n = 10; loop { let n -= 2; if n == 0 { break; } echo n, PHP_EOL; }
  • 31.
    Zephir – ControlStructures let items = ["a": 1, "b": 2, "c": 3, "d": 4]; for key, value in items { echo key, " : ", value, PHP_EOL; } for key, value in reverse items { echo key, " : ", value, PHP_EOL; }
  • 32.
    Zephir – ControlStructures string fullName = "Mark Baker"; char character; for character in fullName { echo character , PHP_EOL; } for character in reverse fullName { echo character , PHP_EOL; }
  • 33.
    Zephir – ControlStructures let items = ["a": 1, "b": 2, "c": 3, "d": 4]; for key, _ in items { echo key, PHP_EOL; } The value element in the for loop doesn’t need to be declared
  • 34.
    Zephir – Exceptions try{ // exceptions can be thrown here if (firstCase) { throw new RuntimeException("This is an exception"); } else { throw "Untyped Exception"; } } catch RuntimeException|Exception, e { // handle exception echo e->getMessage(); }
  • 35.
    Special Features ofZephir Type Hints Object/Interface Type Hints public function injectFilter(<AppFilterInterface> filter) { //... } Similar to the existing type hints in PHP, although notice the syntax differences
  • 36.
    Special Features ofZephir Type Hints “Scalar” Type Hints public function filterText(string text, boolean escape=false) { //... } Allows “compatible” types, e.g. this->filterText(1234, 0); Will try to convert the data passed to the type-hinted datatype
  • 37.
    Special Features ofZephir Type Hints Strict Scalar Hints public function filterText(string! text, boolean escape=false) { //... } this->filterText(1234, 0); Will throw an Exception
  • 38.
    Special Features ofZephir Return Type Hints public function getClassFromFactory() -> <AppMyInterface> { //... } Similar to the return type hints introduced in PHP 7, although notice the syntax differences function isValidStatusCode(int $statusCode): bool { //... }
  • 39.
    Special Features ofZephir Read-Only Arguments public function filterText(const string text, boolean escape=false) { //... } Used for compiler optimisations
  • 40.
    Special Features ofZephir Named Arguments public function crop(width = 600, height = 400) { //... } this->crop(height: 200); this->crop(height: 300, width: 400); Adds a slight performance overhead
  • 41.
    Zephir – Pitfalls Silentcompilation failures $ zephir compile helloworld/ ext/ /helloworld ## zephir generates C source code here /modules ## zephir builds the PHP Extension here helloworld/ compile-errors.log ## Always check this file compile.log config.json
  • 42.
    Zephir – Pitfalls UnsupportedFeatures of PHP Array Dereferencing Callbacks can’t use “use”
  • 43.
    Zephir – Pitfalls Badassumptions from lazy PHP practises In PHP, a pass-by-reference variable in an expression like $validComplex = preg_match('/^...$/ui', $complexNumber, $complexParts); will automatically created $complexParts if it doesn't exist; but Zephir won't do this, so you need to explicitly create it in advance var complexParts; let validComplex = preg_match("/^....$/ui", complexNumber, complexParts);
  • 44.
    Zephir – Pitfalls Overly-Complexor Ambiguous Syntax An expression like if (!is_object($complex) || !$complex instanceof Complex) { … } Might logically be translated to Zephir as if !is_object(complex) || !complex instanceof Complex { … } but Zephir has a different precedence to PHP for instanceof, so you need to do if !is_object(complex) || !(complex instanceof Complex) { … } otherwise it executes !complex and then tests the result of that (always a boolean) for instanceOf Complex cf. https://github.com/phalcon/zephir/issues/277
  • 45.
    Zephir – Utilitiesand Helpers PHP to Zephir https://github.com/fezfez/php-to-zephir
  • 46.
    Zephir – Utilitiesand Helpers $ zephir init helloworld $ cd helloworld $ /home/vagrant/vendor/bin/php-to-zephir phpToZephir:convertDir <path to PHP source code>
  • 47.
  • 48.
    Zephir – Testing $cd helloworld helloworld/ ext/ /helloworld /modules run-tests.php ## PHP Test execution script helloworld/ compile-errors.log compile.log config.json
  • 49.
    Zephir – Testing $cd ext/modules $ php run-tests.php *.phpt <directory with test files> $ php run-tests.php --help Useful Option -c <filename> ## Custom php.ini file to be used
  • 50.
    Zephir – Testing $cat helloWorldTest001.phpt --TEST-- Test Hello World display using helloworld extension --FILE-- <?php $instance = new HelloWorldgreetings(); $instance->english(); --EXPECT-- Hello World
  • 51.
    Zephir – Testing $php run-tests.php *.phpt <directory with test files> … ===================================================================== Running selected tests. PASS Test Hello World display using helloworld extension [/srv/phpnw2015/helloworld/tests/helloWorldTest-001.phpt] ===================================================================== Number of tests : 1 1 Tests skipped : 0 ( 0.0%) -------- Tests warned : 0 ( 0.0%) ( 0.0%) Tests failed : 0 ( 0.0%) ( 0.0%) Expected fail : 0 ( 0.0%) ( 0.0%) Tests passed : 1 (100.0%) (100.0%) --------------------------------------------------------------------- Time taken : 0 seconds =====================================================================
  • 52.
  • 53.
    Useful Zephir Links ZephirDocumentation http://docs.zephir-lang.com/ Zephir Blog http://blog.zephir-lang.com/