53
Zephir A WIND OF CHANGE FOR WRITING PHP EXTENSIONS

Zephir - A Wind of Change for writing PHP extensions

Embed Size (px)

Citation preview

Page 1: Zephir - A Wind of Change for writing PHP extensions

ZephirA WIND OF CHANGE FOR WRITING PHP EXTENSIONS

Page 2: 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.

Page 3: Zephir - A Wind of Change for writing PHP extensions

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.

Page 4: Zephir - A Wind of Change for writing PHP extensions

What is Zephir? In a nutshell

Zephir makes it easy for high-level developers write low-level PHP Extensions.

Page 5: Zephir - A Wind of Change for writing 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

Page 6: Zephir - A Wind of Change for writing PHP extensions

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.

Page 7: Zephir - A Wind of Change for writing PHP extensions

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.

Page 8: Zephir - A Wind of Change for writing PHP extensions

Why might I write an Extension? Performance comparison

HHVM vs Zephir vs PHPhttps://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

Page 9: Zephir - A Wind of Change for writing PHP extensions

What is Zephir? http://zephir-lang.com/ https://github.com/phalcon/zephir

Page 10: Zephir - A Wind of Change for writing PHP extensions

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

Page 11: Zephir - A Wind of Change for writing PHP extensions

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

Page 12: Zephir - A Wind of Change for writing PHP extensions

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

Page 13: Zephir - A Wind of Change for writing PHP extensions

Zephir – Installation (Ubuntu) $ git clone https://github.com/phalcon/zephir

$ cd zephir

$ ./install-json

$ ./install -c

$ cd ..

$ zephir version

0.8.0a

Page 14: Zephir - A Wind of Change for writing PHP extensions

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

Page 15: Zephir - A Wind of Change for writing PHP extensions

Zephir – First Steps $ zephir init helloworld

$ ls helloworld

helloworld/

ext/

helloworld/ ## Our zephir .zep files go here

config.json ## Configuration file for our extension

Page 16: Zephir - A Wind of Change for writing PHP extensions

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": [] }

Page 17: Zephir - A Wind of Change for writing PHP 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

Page 18: Zephir - A Wind of Change for writing PHP extensions

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; } }

Page 19: Zephir - A Wind of Change for writing PHP extensions

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

Page 20: Zephir - A Wind of Change for writing PHP extensions

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

Page 21: Zephir - A Wind of Change for writing PHP extensions

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

Page 22: Zephir - A Wind of Change for writing PHP extensions

Zephir – First Steps $ cat helloworld.php

<?php

$instance = new \HelloWorld\greetings();

$instance->english();

$ php helloworld.php

Hello World

Page 23: Zephir - A Wind of Change for writing PHP extensions

Zephir – Variables Variable names don’t begin with a $

Variables must be pre-defined/declaredvar 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"];

Page 24: Zephir - A Wind of Change for writing PHP extensions

Zephir – Variables Variable variables do not exist in Zephir

But they can be “simulated”//Set variable $name in PHPlet {"name"} = "hello";

//Set variable $price in PHPlet name = "price";let {name} = 10.2;

Page 25: Zephir - A Wind of Change for writing PHP extensions

Zephir – Variable Types Dynamic Typed Variables

Like PHP variables, and can change datatype between the different variable types supported by PHPDeclared with the keyword “var”

var name = "Mark";

Static Typed VariablesA subset of C-Datatypes

boolean, int, uint, char, uchar, long, ulong, string, arrayCan’t change datatype once declaredDeclared with the appropriate datatype name

uint counter = 1;

Page 26: Zephir - A Wind of Change for writing PHP extensions

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;

Page 27: Zephir - A Wind of Change for writing PHP extensions

Zephir – Arrays Array variables can be declared using the keywords “var” or “array”:

var a = []; // dynamic variablearray 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];

Page 28: Zephir - A Wind of Change for writing PHP extensions

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

Page 29: Zephir - A Wind of Change for writing PHP extensions

Zephir – Control Structures let counter = 0; while counter < 10 { echo counter, PHP_EOL; let counter += 1; }

Brackets around the evaluated condition are optional

Page 30: Zephir - A Wind of Change for writing PHP extensions

Zephir – Control Structures let n = 10; loop { let n -= 2; if n == 0 { break; } echo n, PHP_EOL; }

Page 31: Zephir - A Wind of Change for writing PHP extensions

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; }

Page 32: Zephir - A Wind of Change for writing PHP extensions

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; }

Page 33: Zephir - A Wind of Change for writing PHP extensions

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

Page 34: Zephir - A Wind of Change for writing PHP extensions

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(); }

Page 35: Zephir - A Wind of Change for writing PHP extensions

Special Features of Zephir Type Hints

Object/Interface Type Hintspublic function injectFilter(<App\FilterInterface> filter){ //...}

Similar to the existing type hints in PHP, although notice the syntax differences

Page 36: Zephir - A Wind of Change for writing PHP extensions

Special Features of Zephir Type Hints

“Scalar” Type Hintspublic 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

Page 37: Zephir - A Wind of Change for writing PHP extensions

Special Features of Zephir Type Hints

Strict Scalar Hintspublic function filterText(string! text, boolean escape=false){ //...}

this->filterText(1234, 0);

Will throw an Exception

Page 38: Zephir - A Wind of Change for writing PHP extensions

Special Features of Zephir Return Type Hints

public function getClassFromFactory() -> <App\MyInterface> { //...}

Similar to the return type hints introduced in PHP 7, although notice the syntax differences

function isValidStatusCode(int $statusCode): bool {

//...

}

Page 39: Zephir - A Wind of Change for writing PHP extensions

Special Features of Zephir Read-Only Arguments

public function filterText(const string text, boolean escape=false){ //...}

Used for compiler optimisations

Page 40: Zephir - A Wind of Change for writing PHP extensions

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

Page 41: Zephir - A Wind of Change for writing PHP extensions

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

Page 42: Zephir - A Wind of Change for writing PHP extensions

Zephir – Pitfalls Unsupported Features of PHP

Array DereferencingCallbacks can’t use “use”

Page 43: Zephir - A Wind of Change for writing PHP extensions

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 advancevar complexParts;

let validComplex = preg_match("/^....$/ui", complexNumber, complexParts);

Page 44: Zephir - A Wind of Change for writing PHP extensions

Zephir – Pitfalls Overly-Complex or Ambiguous Syntax

An expression likeif (!is_object($complex) || !$complex instanceof Complex) { … }

Might logically be translated to Zephir asif !is_object(complex) || !complex instanceof Complex { … }

but Zephir has a different precedence to PHP for instanceof, so you need to doif !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

Page 45: Zephir - A Wind of Change for writing PHP extensions

Zephir – Utilities and Helpers PHP to Zephir

https://github.com/fezfez/php-to-zephir

Page 46: Zephir - A Wind of Change for writing PHP extensions

Zephir – Utilities and Helpers $ zephir init helloworld

$ cd helloworld

$ /home/vagrant/vendor/bin/php-to-zephir phpToZephir:convertDir \

<path to PHP source code>

Page 47: Zephir - A Wind of Change for writing PHP extensions

Zephir – Testing

Page 48: Zephir - A Wind of Change for writing PHP extensions

Zephir – Testing $ cd helloworld

helloworld/ ext/ /helloworld /modules run-tests.php ## PHP Test execution script helloworld/ compile-errors.log compile.log config.json

Page 49: Zephir - A Wind of Change for writing PHP extensions

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

Page 50: Zephir - A Wind of Change for writing PHP extensions

Zephir – Testing $ cat helloWorldTest001.phpt

--TEST-- Test Hello World display using helloworld extension --FILE-- <?php

$instance = new \HelloWorld\greetings();

$instance->english(); --EXPECT-- Hello World

Page 51: Zephir - A Wind of Change for writing PHP extensions

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 =====================================================================

Page 52: Zephir - A Wind of Change for writing PHP extensions

Zephir – Testing https://qa.php.net/write-test.php https://qa.php.net/phpt_details.php

Page 53: Zephir - A Wind of Change for writing PHP extensions

Useful Zephir Links Zephir Documentation

http://docs.zephir-lang.com/

Zephir Bloghttp://blog.zephir-lang.com/