Zephir PHP Extension Tutorial Documentation
Zephir PHP Extension Tutorial Documentation
Release 0.6.3
Zephir Team
1 Reference 1
1.1 Welcome! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Why Zephir? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Introducing Zephir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.5 Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.6 Basic Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.7 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.8 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.9 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.10 Classes and Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.11 Built-In Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
1.12 Control Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
1.13 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.14 Calling Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.15 Closures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
1.16 Custom optimizers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.17 Configuration File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.18 Extension Globals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.19 Phpinfo() sections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
1.20 Static Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
1.21 Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
1.22 Compiler Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
1.23 License . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
2 Other Formats 59
Index 61
i
ii
CHAPTER 1
Reference
1.1 Welcome!
Welcome to Zephir, an open source, high-level/domain specific language designed to ease the creation and maintain-
ability of extensions for PHP with a focus on type and memory safety.
The following code registers a class with a method that filters variables returning its alphabetic characters:
namespace MyLibrary;
/**
* Filter
*/
class Filter
{
/**
* Filters a string returning its alpha characters
*
* @param string str
*/
public function alpha(string str)
{
char ch; string filtered = "";
for ch in str {
if (ch >= a && ch <= z) || (ch >= A && ch <= Z) {
1
Zephir Documentation, Release 0.6.3
return filtered;
}
}
Todays PHP applications must balance a number of concerns including stability, performance and functionality. Every
PHP application is based on a set of common components that are also base for most of the application.
These common components are libraries/frameworks or a combination of them. Once installed, frameworks rarely
change, being the foundation of the application they must be highly functional and also very fast.
Getting fast and robust libraries can be complicated due to high levels of abstraction that are typically implemented on
them. Given the condition that base libraries or frameworks rarely change, there is an opportunity to build extensions
that provide this functionality taking advantage of the compilation improving performance and resource consumption.
With Zephir, you can implement object-oriented libraries/frameworks/applications that can be used from PHP gaining
important seconds that can make your application faster while improving the user experience.
PHP is one of the most popular languages in use for the development of web applications. Dynamically typed and
interpreted languages like PHP offer very high productivity due to their flexibility.
Since version 4 and then 5, PHP is based on the Zend Engine implementation. This is a virtual machine that executes
the PHP code from its bytecode representation. Zend Engine is almost present in every PHP installation in the world,
with Zephir, you can create extensions for PHP running under the Zend Engine.
PHP is hosting Zephir, so they obviously have a lot of similarities, however; they have important differences that give
Zephir its own personality. For example, Zephir is more strict, and it could be make you less productive compared to
PHP due to the compilation step.
C is one of the most powerful and popular languages ever created. In fact, PHP is written in C, which is one of the
reasons why PHP extensions are available for it. C gives you the freedom to manage memory, use low level types and
even inline assembly routines.
However, developing big applications in C can take much longer than expected compared to PHP or Zephir and some
errors can be tricky to find if you arent an experienced developer.
Zephir was designed to be safe, so it doesnt implement pointers or manual memory management, so if youre a C
programmer, you will feel Zephir less powerful but more friendly than C.
2 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
Compilation usually slows the development down; you will need a bit more of patience to make your code compiled
before running it. Moreover, the interpretation tends to reduce the performance in favor of productivity. In some cases,
there is no any noticeable difference between the speed of the interpreted and compiled code.
Zephir requires compilation of your code, however, the functionality is used from PHP that is interpreted.
Once the code is compiled is not necessary to do so, however, interpreted code is interpreted each time it is run. A
developer can decide which parts of your application should be in Zephir and which not.
In general speaking, in a static typed language, a variable is bound to a particular type for its lifetime. Its type cant be
changed and it can only reference type-compatible instances and operations. Languages like C/C++ were implemented
with the scheme:
int a = 0;
a = "hello"; // not allowed
In dynamic typing, the type is bound to the value, not the variable. So, a variable might refer to a value of a type, then
be reassigned later to a value of an unrelated type. Javascript/PHP are examples of a dynamic typed language:
var a = 0;
a = "hello"; // allowed
Despite their productivity advantages, dynamic languages may not be the best choices for all applications, particularly
for very large code bases and high-performance applications.
Optimizing the performance of a dynamic language like PHP is more challenging than for a static language like C. In
a static language, optimizers can exploit the type information to make decisions. In a dynamic language, fewer such
clues are available for the optimizer, making optimization choices harder.
While recent advancements in optimizations for dynamic languages are promising (like JIT compilation), they lag
behind the state of the art for static languages. So, if you require very high performance, static languages are probably
a safer choice.
Another small benefit of static languages is the extra checking the compiler performs. A compiler cant find logic
errors, which are far more significant, but a compiler can find errors in advance that in a dynamic language only can
be found in runtime.
Zephir is both statically and dynamically typed allowing you to take advantage from both sides where possible.
Zephir offers native code generation (currently via compilation to C), a compiler like gcc/clang/vc++ optimizes and
compiles the code down to machine code. The following graph shows how the process works:
In addition to the ones provided by Zephir, Over time, compilers have been implemented and matured a number of
optimizations that improve the performance of compiled applications:
GCC optimizations
LLVM passes
Visual C/C++ optimizations
In some circumstances, the compilation does not significantly improve performance, this may be because the bot-
tleneck is located in the I/O bound of the application (quite likely) rather than compute/memory bound. However,
compiling code could also bring some level of intelectual protection to your application. With Zephir, producing
native binaries, you also get the ability to hide the code to users or customers.
1.2.7 Conclusion
Zephir was not created to replace PHP or C, instead of this, we think it is a complement to them, allowing developers
to venture into code compilation and static typing. Zephir is precisely an attempt to join good things from the C and
PHP worlds, looking for opportunities to make their applications faster.
Zephir is a language that addresses the major needs of a PHP developer trying to write and compile code that can be
executed by PHP. It is a dynamically/statically typed, some of its features can be familiar to PHP developers.
The name Zephir is a contraction of the words Zend Engine/PHP/Intermediate. While this suggests that the pronunci-
ation should be zephyr, the creators of Zephir actually pronounce it zaefire.
Every language has its own Hello World! sample, in Zephir this introductory example showcases some important
features of this language.
Code in Zephir must be placed in classes. This language is intended to create object-oriented libraries/frameworks, so
code out of a class is not allowed. Also, a namespace is required:
namespace Test;
/**
* This is a sample class
*/
class Hello
{
/**
4 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
Once this class is compiled it produce the following code that is transparently compiled by gcc/clang/vc++:
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_test.h"
#include "test.h"
#include "kernel/main.h"
/**
* This is a sample class
*/
ZEPHIR_INIT_CLASS(Test_Hello) {
ZEPHIR_REGISTER_CLASS(Test, Hello, hello, test_hello_method_entry, 0);
return SUCCESS;
}
/**
* This is a sample method
*/
PHP_METHOD(Test_Hello, say) {
php_printf("%s", "Hello World!");
}
Actually, it is not expected that a developer that uses Zephir must know or even understand C, however, if you have
any experience with compilers, php internals or the C language itself, it would provide a more clear sceneario to the
developer when working with Zephir.
In the following examples, well describe just enough of the details, so you understand whats going on. The goal
is to give you a sense of what programming in Zephir is like. Well explore the details of the features in subsequent
chapters.
The following example is very simple, it implements a class and a method with a small program that checks the types
of an array
Lets examine the code in detail, so we can begin to learn Zephir syntax. There are a lot of details in just a few lines
of code! Well explain the general ideas here:
namespace Test;
/**
* MyTest (test/mytest.zep)
*/
class MyTest
{
/* Create an array */
let myArray = ["hello", 0, 100.25, false, null];
return myArray;
}
}
In the method, the first lines use the var and int keywords are used to declare a variable in the local scope. Every
variable used in a method must be declared with its respective type. This declaration is not optional, it helps the
compiler to report you about mistyped variables or about the use of variables out of their scope which usually ends in
runtime errors.
Dynamic variables are declared with the keyword var. These variables can be assigned and reassigned to different
types. On the other hand, we have i and length integer static typed variables that can only have values of this type
in the entire program execution.
In contrast with PHP, you are not required to put a dollar sign ($) in front of variable names.
Zephir follows the same comment conventions as Java, C#, C++, etc. A //comment goes to the end of a line, while a
/* comment */ can cross line boundaries.
Variables are by default immutable, this means that Zephir expects that most variables stay unchanged. Variables that
maintain their initial value can be optimized down by the compiler to static constants. When the variable value needs
to be changed, the keyword let must be used:
/* Create an array */
let myArray = ["hello", 0, 100.25, false, null];
By default, arrays are dynamic like in PHP, they may contain values of different types. Functions from the PHP
userland can be called in Zephir code, in the example the function count was called, the compiler can performs
optimizations like avoid this call because it already knows the size of the array:
/* Count the array into a int variable */
let length = count(myArray);
Parentheses in control flow statements are optional, you can also use them if you feel more confortable.
while i < length {
echo typeof myArray[i], "\n";
let i++;
}
PHP only works with dynamic variables, methods always return dynamic variables, this means that if a static typed
variable is returned, in the PHP side, you will get a dynamic variable that can be used in PHP code. Note that memory
6 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
is automatically managed by the compiler, so you dont need to allocate or free memory like in C, working in a similar
way than PHP.
1.4 Installation
1.4.1 Prerequisites
To build a PHP extension and use Zephir you need the following 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
If youre using Ubuntu, you can install the required packages this way:
$ sudo apt-get update
$ sudo apt-get install git gcc make re2c php5 php5-json php5-dev libpcre3-dev
Since Zephir is written in PHP you need to have installed a recent version of PHP and it must be available in your
console:
$ php -v
PHP 5.5.7 (cli) (built: Dec 14 2013 00:44:43)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2013 Zend Technologies
Also, make sure you have also the PHP development libraries installed along with your PHP installation:
$ phpize -v
Configuring for:
PHP Api Version: 20121113
Zend Module Api No: 20121212
Zend Extension Api No: 220121212
You dont have to necessarely see the exact above output but its important that these commands are available to start
developing with Zephir.
1.4. Installation 7
Zephir Documentation, Release 0.6.3
$ cd zephir
$ ./install-json
$ ./install -c
You can ommit the ./install-json step if you already have json-c installed
1.5 Tutorial
Zephir and this book are intended for PHP developers which want to create C-extensions with a lower complexity.
We assume that you are experienced in one or more other programming languages. We draw parallels to features in
PHP, C, Javascript, and other languages. If you know any of these languages, well point out similar features in Zephir,
as well as many features that are new or different.
If you have successfully installed Zephir, you must be able to execute the following command in your console:
$ zephir help
If everything is well, you should see the following help in your screen:
_____ __ _
/__ / ___ ____ / /_ (_)____
/ / / _ \/ __ \/ __ \/ / ___/
/ /__/ __/ /_/ / / / / / /
/____/\___/ .___/_/ /_/_/_/
/_/
Usage:
command [options]
Available commands:
api Generates a HTML API
build Generate/Compile/Install a Zephir extension
builddev Generate/Compile/Install a Zephir extension in development mode
clean Cleans the generated object files in compilation
compile Compile a Zephir extension
fullclean Cleans the generated object files in compilation
generate Generates C code from the Zephir code
help Displays this help
init [namespace] Initializes a Zephir extension
install Installs the extension (requires root password)
stubs Generates extension PHP stubs
version Shows the Zephir version
Options:
8 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
The first thing we have to do is generate an extension skeleton, this will provide to our extension the basic structure
we need to start working. In our case, were going to create an extension called utils:
$ zephir init utils
After this, a directory called utils is created on the current working directory:
utils/
ext/
utils/
The directory ext/ (inside utils) contains the code that is going to be used by the compiler to produce the extension.
The another directory created is utils, this directory has the same as our extension. We will place Zephir code in this
directory.
We need to change the working directory to utils to start compiling our code:
$ cd utils
$ ls
ext/ utils/ config.json
The directory listing will also show us a file called config.json, this file contains configuration settings we can use
to alter the behavior of Zephir and/or this extension.
Zephir is designed to generate object-oriented extensions. To start developing functionality we need to add our first
class to the extension.
As in many languages/tools, the first thing we want to do is see a hello world generated by Zephir and check that
everything is well. So our first class will be called Utils\Greeting and it contains a method printing hello world!.
The code for this class must be placed in utils/utils/greeting.zep:
namespace Utils;
class Greeting
{
Now, we need to tell Zephir that our project must be compiled and the extension generated:
$ zephir build
1.5. Tutorial 9
Zephir Documentation, Release 0.6.3
Initially, and only for the first time, a number of internal commands are executed producing the necessary code and
configurations to export this class to the PHP extension, if everything goes well you will see the following message at
the end of the output:
...
Extension installed!
Add extension=utils.so to your php.ini
Dont forget to restart your web server
At the above step, its likely that you would need to supply your root password in order to install the extension. Finally,
the extension must be added to the php.ini in order to be loaded by PHP. This is achieved by adding the initialization
directive: extension=utils.so to it.
Now that the extension was added to your php.ini, check whether the extension is being loaded properly by executing
the following:
$ php -m
[PHP Modules]
Core
date
libxml
pcre
Reflection
session
SPL
standard
tokenizer
utils
xdebug
xml
Extension utils must be part of the output indicating that the extension was loaded correctly. Now, lets see our
hello world directly executed by PHP. To accomplish this, you can create a simple PHP file calling the static method
we have just created:
<?php
The hello world class was fine to check if our enviroment was right, now, lets create some more useful classes.
The first useful class we are going to add to this extension will provide filtering facilities to users. This class is called
Utils\Filter and its code must be placed in utils/utils/filter.zep:
A basic skeleton to this class is the following:
namespace Utils;
class Filter
{
10 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
The class contains filtering methods that help users to filter unwanted caracters from strings. The first method is called
alpha and its purpose is to filter only those characters that are ascii basic letters. To begin, we are just going to
traverse the string printing every byte to the standard output:
namespace Utils;
class Filter
{
for ch in str {
echo ch, "\n";
}
$f = new Utils\Filter();
$f->alpha("hello");
Checking every character in the string is straightforward, we now just could create another string with the right filtered
characters:
class Filter
{
for ch in str {
if (ch >= a && ch <= z) || (ch >= A && ch <= Z) {
let filtered .= ch;
}
}
return filtered;
}
}
1.5. Tutorial 11
Zephir Documentation, Release 0.6.3
$f = new Utils\Filter();
echo $f->alpha("!he#02l3121lo."); // prints "hello"
In the following screencast you can watch how to create the extension explained in this tutorial:
1.5.6 Conclusion
This is a very simple tutorial and as you can see, its easy to start building extensions using Zephir. We invite you to
continue reading the manual so that you can discover additional features offered by Zephir!
In this chapter, well discuss the organization of files and namespaces, variable declarations, miscellaneous syntax
conventions, and a few other concepts.
In PHP, you can place the code in any file without a specific structure. In Zephir, every file must contain a class (and
just one class). Every class must have a namespace and the directory structure must match the names of classes and
namespaces used.
For example, given the following structure, the classes in each file must be:
mylibrary/
router/
exception.zep # MyLibrary\Router\Exception
router.zep # MyLibrary\Router
Class in mylibrary/router.zep:
namespace MyLibrary;
class Router
{
Class in mylibrary/router/exception.zep:
namespace MyLibrary\Router;
Zephir will raise a compiler exception if a file or class is not located at the expected file or vice versa.
You may have already noticed that there were very few semicolons in the code examples in the previous chapter. You
can use semicolons to separate statements and expressions, as in Java, C/C++, PHP, and similar languages:
12 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
1.6.3 Comments
Zephir supports C/C++ comments, these are one line comments with // and multi line comments with /* ... */:
// this is one line comment
/**
* multi-line comment
*/
In most languages, comments are simply text ignored by the compiler/interpreter. In Zephir, multi-line comments are
also used as docblocks, and theyre exported to the generated code, so theyre part of the language!.
If a docblock is not located where is expected, the compiler will throw an exception.
In Zephir, all variables used in a given scope must be declared. This process gives important information to the
compiler to perform optimizations and validations. Variables must be unique identifiers, and they cannot be reserved
words.
//Declaring variables for the same type in the same instruction
var a, b, c;
Variables can optionally have an initial compatible default value, you can assign a new value to a variable as often as
you want:
//Declaring variables with default values
var a = "hello", b = 0, c = 1.0;
int d = 50; bool some = true;
All variables declared are locally scoped to the method where they were declared:
namespace Test;
class MyClass
{
return a + b;
}
Zephir doesnt support global variables, accessing global variables from the PHP userland is not allowed. However,
you can access the PHPs super-globals as follows:
//Getting a value from _POST
let price = _POST["price"];
Every method or context in PHP has a symbol table that allows to write variables in a very dynamic way:
<?php
$b = 100;
$a = "b";
echo $$a; // prints 100
Zephir does not implement this feature since all variables are compiled down to low-level variables and there is no
way to know which variables do exist in a specific context. If you want to create a variable in the current PHP symbol
table, you can use the following syntax:
//Set variable $name in PHP
let {"name"} = "hello";
1.7 Types
Zephir is both dynamic and static typed. In this chapter we highlight the supported types and its behavior:
Dynamic variables are exactly like the ones in PHP, they can be assigned and reassigned to different types without
restriction.
14 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
A dynamic variable must be declared with the keyword var, the behavior is nearly the same as in PHP:
var a, b, c;
// Initialize variables
let a = "hello", b = false;
Boolean
Integer
Integer numbers. The size of an integer is platform-dependent, although a maximum value of about two billion is
the usual value (thats 32 bits signed). 64-bit platforms usually have a maximum value of about 9E18. PHP does not
support unsigned integers so Zephir has this restriction too:
var a = 5, b = 10050;
Integer overflow
Contrary to PHP, Zephir does not automatically check for integer overflows, like in C if you are doing operations that
may return a big number you can use types such as unsigned long or float to store them:
unsigned long my_number = 2147483648;
Float/Double
Floating-point numbers (also known as floats, doubles, or real numbers). Floating-point literals are expressions
with zero or more digits, followed by a period (.), followed by zero or more digits. The size of a float is platform-
dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64
bit IEEE format).
1.7. Types 15
Zephir Documentation, Release 0.6.3
Floating point numbers have limited precision. Although it depends on the system, as PHP, Zephir uses the IEEE 754
double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16.
String
A string is series of characters, where a character is the same as a byte. As PHP, Zephir only supports a 256-character
set, and hence does not offer native Unicode support.
var today = "friday";
In Zephir, string literals can only be specified using double quotes (like in C), single quotes are reserved for chars.
The following escape sequences are supported in strings:
Sequence Description
\t Horizontal tab
\n Line feed
\r Carriage return
\\ Backslash
\ double-quote
var today = "\tfriday\n\r",
tomorrow = "\tsaturday";
In Zephir, strings dont support variable parsing like in PHP, you can use concatenation instead:
var name = "peter";
Arrays
The array implementation in Zephir is basically the same as in PHP: Ordered maps optimized for several different
uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack,
queue, and probably more. As array values can be other arrays, trees and multidimensional arrays are also possible.
The syntax to define arrays is slightly different than in PHP:
//Square braces must be used to define arrays
let myArray = [1, 2, 3];
Objects
Zephir allows to instantiate, manipulate, call methods, read class constants, etc from PHP objects:
16 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
Static typing allows the developer to declare and use some variable types available in C. Variables cant change their
type once theyre declared as dynamic types. However, they allow the compiler to do a better optimization job. The
following types are supported:
Type Description
boolean A boolean expresses a truth value. It can be either true or false.
integer Signed integers. At least 16 bits in size.
unsigned integer Unsigned integers. At least 16 bits in size.
char Smallest addressable unit of the machine that can contain basic character set.
unsigned char Same size as char, but guaranteed to be unsigned.
long Long signed integer type. At least 32 bits in size.
unsigned long Same as long, but unsigned.
float/double Double precision floating-point type. The size is platform-dependent.
string A string is series of characters, where a character is the same as a byte.
array An structure that can be used as hash, map, dictionary, collection, stack, etc.
Boolean
A boolean expresses a truth value. It can be either true or false. Contrary to the dynamic behavior static boolean
types remain boolean (true or false) no mater what value is assigned to them:
boolean a;
let a = true,
a = 100, // automatically casted to true
a = null, // automatically casted to false
a = "hello"; // throws a compiler exception
Integer/Unsigned Integer
Integer values are like the integer member in dynamic values. Values assigned to integer variables remain integer:
int a;
let a = 50,
a = -70,
a = 100.25, // automatically casted to 100
a = null, // automatically casted to 0
a = false, // automatically casted to 0
a = "hello"; // throws a compiler exception
Unsigned integers are like integers but they dont have sign, this means you cant store negative numbers in these sort
of variables:
let a = 50,
a = -70, // automatically casted to 70
a = 100.25, // automatically casted to 100
a = null, // automatically casted to 0
1.7. Types 17
Zephir Documentation, Release 0.6.3
Unsigned integers are twice bigger than standard integers, assign unsigned integers to integers may represent loss of
data:
uint a, int b;
let a = 2147483648,
b = a, // possible loss of data
Long/Unsigned Long
Long variables are twice bigger than integer variables, thus they can store bigger numbers, As integers values assigned
to long variables are automatically casted to this type:
long a;
let a = 50,
a = -70,
a = 100.25, // automatically casted to 100
a = null, // automatically casted to 0
a = false, // automatically casted to 0
a = "hello"; // throws a compiler exception
Unsigned longs are like longs but they arent signed, this means you cant store negative numbers in these sort of
variables:
let a = 50,
a = -70, // automatically casted to 70
a = 100.25, // automatically casted to 100
a = null, // automatically casted to 0
a = false, // automatically casted to 0
a = "hello"; // throws a compiler exception
Unsigned longs are twice bigger than standard longs, assign unsigned longs to longs may represent loss of data:
ulong a, long b;
let a = 4294967296,
b = a, // possible loss of data
Char/Unsigned Char
Char variables are the smallest addressable unit of the machine that can contain basic character set. Every char
variable represents every character in a string:
char ch, string name = "peter";
18 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
String
A string is series of characters, where a character is the same as a byte. As in PHP it only supports a 256-character set,
and hence does not offer native Unicode support.
When a variable is declared string it never changes its type:
string a;
let a = "",
a = "hello", //string literals must be enclosed in double quotes
a = A, // converted to string "A"
a = null; // automatically casted to ""
1.8 Operators
Zephirs set of operators are similar to the ones PHP and also inherits some of their behaviors.
Comparison operators depend on the type of variables compared, for example, if both compared operands are dynamic
variables the behavior is the same as in PHP:
a == b Equal TRUE if a is equal to b after type juggling.
a === b Identical TRUE if a is equal to b, and they are of the same type.
a != b Not equal TRUE if a is not equal to b after type juggling.
a <> b Not equal TRUE if a is not equal to b after type juggling.
a !== b Not identical TRUE if a is not equal to b, or they are not of the same type.
a<b Less than TRUE if a is strictly less than b.
a>b Greater than TRUE if a is strictly greater than b.
a <= b Less than or equal to TRUE if a is less than or equal to b.
a >= b Greater than or equal to TRUE if a is greater than or equal to b.
Example:
if a == b {
return 0;
} else {
if a < b {
return -1;
} else {
1.8. Operators 19
Zephir Documentation, Release 0.6.3
return 1;
}
}
20 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
Empty
This operator allows to check whether an expression is empty. Empty means the expression is null, is an empty string
or an empty array:
let someVar = "";
if empty someVar {
echo "is empty!";
}
Isset
This operator checks whether a property or index has been defined in an array or object:
let someArray = ["a": 1, "b": 2, "c": 3];
if isset someArray["b"] { // check if the array has an index "b"
echo "yes, it has an index b\n";
}
Note that isset in Zephir works more like PHPs function array_key_exists, isset in Zephir returns true even if the
array index or property is null.
Fetch
Fetch is an operator that reduce a common operation in PHP into a single instruction:
<?php
if (isset($myArray[$key])) {
$value = $myArray[$key];
echo $value;
}
Fetch only returns true if the key is a valid item in the array, only in that case, value is populated.
Typeof
This operator check variable type. Typeof could works like comparison operator:
if (typeof str == "string") { // or !=
echo str;
}
1.8. Operators 21
Zephir Documentation, Release 0.6.3
Be careful, if you want to check is object callable you allways have to use typeof as comparison operator.
Type Hints
Zephir always tries to check whether an object implements methods and properties called/accessed on a variable that
is inferred to be an object:
let o = new MyObject();
However, due to the dynamism inherited from PHP, sometimes it is not easy to know the class of an object so Zephir
can not produce errors reports effectively. A type hint tells the compiler which class is related to a dynamic variable
allowing the compiler to perform more compilation checks:
// Tell the compiler that "o"
// is an instance of class MyClass
let o = <MyClass> this->_myObject;
o->myMethod();
These type hints are weak, this means the program does not check if the class is in fact an instance of the specified
class or whether it implements the specified interface. If you want it to check this every time in execution:
// Always check if the property is an instance
// of MyClass before the assignment
let o = <MyClass!> this->_myObject;
o->myMethod();
What is branch prediction? Check this article out. In environments where performance is very important, it may be
useful to introduce these hints.
Consider the following example:
let allPaths = [];
for path in this->_paths {
if path->isAllowed() == false {
throw new App\Exception("error!!");
} else {
let allPaths[] = path;
}
}
The authors of the above code, know in advance that the condition that throws the exception is unlikely to happen.
This means that 99.9% of the time, our method executes that condition, but it is probably never evaluated as true. For
the processor, this could be hard to know, so we could introduce a hint there:
let allPaths = [];
for path in this->_paths {
if unlikely path->isAllowed() == false {
throw new App\Exception("error!!");
22 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
} else {
let allPaths[] = path;
}
}
1.9 Arrays
Array manipulation in Zephir provides a way to use PHP arrays. An array is an implementation of a hash table.
Arrays are updated in the same way as PHP using square brackets:
//Updating an array with a string key
let elements["foo"] = "bar";
1.9. Arrays 23
Zephir Documentation, Release 0.6.3
Zephir promotes object-oriented programming, this is why you can only export methods and classes in extensions,
also you will see that most of the time, runtime errors raise exceptions instead of fatal errors or warnings.
1.10.1 Classes
Every Zephir file must implement a class or an interface (and just once). A class structure is very similar to a PHP
class:
namespace Test;
/**
* This is a sample class
*/
class MyClass
{
Class Modifiers
/**
* This class cannot be extended by another class
24 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
*/
final class MyClass
{
/**
* This class cannot be instantiated
*/
abstract class MyClass
{
The function keyword introduces a method. Methods implements the usual visibility modifiers available in PHP,
explicity set a visibility modifier is mandatory in Zephir:
namespace Test;
class MyClass
{
class MyClass
{
/**
* All parameters are required
*/
public function doSum1(a, b)
{
return a + b;
}
/**
* Only a is required, b is optional and it has a default value
*/
public function doSum2(a, b = 3)
{
return a + b;
}
/**
* Both parameters are optional
*/
public function doSum3(a = 1, b = 2)
{
return a + b;
}
/**
* Parameters are required and their values must be integer
*/
public function doSum4(int a, int b)
{
return a + b;
}
/**
* Static typed with default values
*/
public function doSum4(int a = 4, int b = 2)
{
return a + b;
}
}
Zephir ensures that the value of a variable remains of the type the variable was declared of. This assurance the compiler
does when a variable has a null value makes Zephir convert the null value to the most approximate value:
public function foo(int a = null)
{
echo a; // if "a" is not passed it prints 0
}
26 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
Supported Visibilities
Public: Methods marked as public are exported to the PHP extension, this means that public methods are
visible to the PHP code as well to the extension itself.
Protected: Methods marked as protected are exported to the PHP extension, this means that protected methods
are visible to the PHP code as well to the extension itself. However, protected methods can only be called in the
scope of the class or in classes that inherit them.
Private: Methods marked as private are not exported to the PHP extension, this means that private methods
are only visible to the class where theyre implemented.
Supported Modifiers
Getter/Setter shortcuts
Like in C#, you can use get/set/toString shortcuts in Zephir, this feature allows to easily write setters and getters for
properties without explictly implementing those methods as such.
For example, without shortcuts we could find code like:
namespace Test;
class MyClass
{
protected myProperty;
{
return this->myProperty;
}
class MyClass
{
protected myProperty {
set, get, toString
};
protected someProperty = 10 {
set, get
};
When the code is compiled those methods are exported as real methods but you dont have to write them one by one.
Methods in classes and interfaces can have return type hints, these will provide useful extra information to the
compiler to inform you about errors in your application. Consider the following example:
namespace App;
class MyClass
{
public function getSomeData() -> string
{
// this will throw a compiler exception
// since the returned value (boolean) does not match
// the expected returned type string
return false;
}
28 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
A method can have more than one return type. When multiple types are defined, the operator | must be used to separate
those types.
namespace App;
class MyClass
{
public function getSomeData(a) -> string | bool
{
if a == false {
return false;
}
return "error";
}
}
Methods can also be marked as void. This means that a method is not allowed to return any data:
public function setConnection(connection) -> void
{
let this->_connection = connection;
}
Why is this useful? Because the compiler can detect if the program is expecting a returning value from these methods
and produce a compiler exception:
let myDb = db->setConnection(connection);
myDb->execute("SELECT * FROM robots"); // this will produce an exception
In Zephir, you can specify the data type of each parameter of a method. By default, these data-types are flexible, this
means that if a value with wrong (but compatible) data-type is passed, Zephir will try to transparently convert it to the
expected one:
public function filterText(string text, boolean escape=false)
{
//...
}
$o->filterText(1111, 1); // OK
$o->filterText("some text", null); // OK
$o->filterText(null, true); // OK
However, passing a wrong type could be often lead to bugs, a bad use of a specific API would produce unexpected
results. You can disallow the automatic conversion by setting the parameter with a strict data-type:
public function filterText(string! text, boolean escape=false)
{
//...
}
Now, most of the calls with a wrong type will cause an exception due to the invalid data types passed:
<?php
By specifying what parameters are strict and what must be flexible, a developer can set the specific behavior he/she
really wants.
Read-Only Parameters
Using the keyword const you can mark parameters as read-only, this helps to respect const-correctness. Parameters
marked with this attribute cannot be modified inside the method:
namespace App;
class MyClass
{
// "a" is read-only
public function getSomeData(const string a)
{
// this will throw a compiler exception
let a = "hello";
}
}
When a parameter is declared as read-only the compiler can make safe assumptions and perform further optimizations
over these variables.
Class member variables are called properties. By default, they act as PHP properties. Properties are exported to the
PHP extension and are visibles from PHP code. Properties implement the usual visibility modifiers available in PHP,
explicity set a visibility modifier is mandatory in Zephir:
namespace Test;
class MyClass
{
public myProperty1;
30 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
protected myProperty2;
private myProperty3;
Within class methods non-static properties may be accessed by using -> (Object Operator): this->property (where
property is the name of the property):
namespace Test;
class MyClass
{
protected myProperty;
Properties can have literal compatible default values. These values must be able to be evaluated at compile time and
must not depend on run-time information in order to be evaluated:
namespace Test;
class MyClass
{
Updating Properties
Zephir checks that properties do exist when a program is accesing them, if a property is not declared you will get a
compiler exception:
CompilerException: Property _optionsx is not defined on class App\MyClass in /Users/scott/utils/a
this->_optionsx = options;
------------^
If you want to avoid this compiler validation or just create a property dynamically, you can enclose the property name
using string quotes:
You can also use a simple variable to update a property, the property name will be taken from the variable:
let someProperty = "myProperty";
let this->{someProperty} = 100;
Reading Properties
Class may contain class constants that remain the same and unchangeable once the extension is compiled. Class
constants are exported to the PHP extension allowing them to be used from PHP.
namespace Test;
class MyClass
{
Class constants can be accessed using the class name and the static operator (::):
namespace Test;
class MyClass
{
32 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
namespace Test;
class MyClass
{
class MyClass
{
class MyClass
{
protected adapter;
Parameters by Name
Zephir supports call methods parameters by name or keyword arguments. Named parameters can be useful if you want
to pass parameters in an arbitrary order, document the meaning of parameters or specify parameters in a more elegant
way.
Consider the following example, a class called Image has a method that receive four parameters:
namespace Test;
class Image
{
public function chop(width = 600, height = 400, x = 0, y = 0)
{
//...
}
}
When the compiler (at compile time) does not know the correct order of these parameters they must be resolved at
runtime, in this case there could be a minimum additional extra overhead:
let i = new {someClass}();
i->chop(y:30, x: 20);
As mentioned before, Zephir promotes object-oriented programming, variables related to static types can be also
handled as objects.
Compare these two methods:
public function binaryToHex(string! s) -> string
{
var o = "", n; char ch;
And:
public function binaryToHex(string! s) -> string
{
var o = "", n; char ch;
34 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
They both have the same functionality, but the second one uses object-oriented programming. Calling methods on
static-typed variables does not have any impact on performance since Zephir internally transforms the code from the
object-oriented version to the procedural version.
1.11.1 String
1.11.2 Array
1.11.3 Char
1.11.4 Integer
Zephir implements a simplified set of control structures present in similar languages like C, PHP etc.
1.12.1 Conditionals
If Statement
if statements evaluates an expression executing this trace if the evaluation is true. Braces are compulsory, an if can
have an optional else clause, multiple if/else constructs can be chained together:
if false {
echo "false?";
} else {
if true {
echo "true!";
} else {
echo "neither true nor false";
}
}
36 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
Switch Statement
A switch evalutes an expression against a series of predefined literal values executing the corresponding case block
or falling back to the default block case:
switch count(items) {
case 1:
case 3:
echo "odd items";
break;
case 2:
case 4:
echo "even items";
break;
default:
echo "unknown items";
}
1.12.2 Loops
While Statement
while denotes a loop that iterates as long as its given condition evaluates as true:
let counter = 5;
while counter {
let counter -= 1;
}
Loop Statement
For Statement
A for loop can also be instructed to traverse an array or string in reverse order:
let items = [1, 2, 3, 4, 5];
for ch in language {
echo "[", ch ,"]";
}
In reverse order:
string language = "zephir"; char ch;
A standard for that traverses a range of integer values can be written as follows:
for i in range(1, 10) {
echo i, "\n";
}
To avoid warnings about unused variables you can use in for statements anonymous variables, by replacing a variable
name with the placeholder _:
// Use the key but ignore the value
for key, _ in data {
echo key, "\n";
}
Break Statement
38 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
Continue Statement
continue is used within looping structures to skip the rest of the current loop iteration and continue execution at the
condition evaluation and then the beginning of the next iteration.
let a = 5;
while a > 0 {
let a--;
if a == 3 {
continue;
}
echo a, "\n";
}
1.12.3 Require
The require statement dynamically includes and evaluates a specified PHP file. Note that files included via Zephir
are interpreted by Zend Engine as normal PHP files. require does not allow to include other zephir files in runtime.
if file_exists(path) {
require path;
}
1.12.4 Let
Let statement is used to mutate variables, properties and arrays. Variables are by default immutable and this instruc-
tion makes them mutable:
let name = "Tony"; // simple variable
let this->name = "Tony"; // object property
let data["name"] = "Tony"; // array index
let self::_name = "Tony"; // static property
1.13 Exceptions
Zephir implements exceptions at a very low level providing a similar behavior like PHP but in compiled code.
When an exception is thrown, a catch block can caught the exception and the developer can provide the proper
handling.
try {
1.13. Exceptions 39
Zephir Documentation, Release 0.6.3
} catch \ Exception, e {
// handle exception
echo e->getMessage();
}
Zephir provides a silent try block that simply ignores any exception produced within the block:
try {
throw new \ Exception("This is an exception");
}
When catching the exception if you dont need a variable for the exception you can safely miss it:
try {
} catch \ Exception {
// handle exception
echo e->getMessage();
}
} catch RuntimeException|Exception, e {
// handle exception
echo e->getMessage();
}
Zephir allows you to throw literals or static typed variables as they were the message of the exception:
throw "Test"; // throw new \Exception("Test");
throw t; // throw new \Exception((string) t);
throw 123; // throw new \Exception((string) 123);
throw 123.123; // throw new \Exception((string) 123.123);
Zephirs exceptions provides the same facilities as in PHP to know where exception happened. Exception::getFile()
and Exception::getLine() returns the location in the Zephir code where the exception has been thrown:
Exception: The static method someMethod doesnt exist on model Robots
File=phalcon/mvc/model.zep Line=4042
#0 /home/scott/test.php(64): Phalcon\Mvc\Model::__callStatic(someMethod, Array)
#1 /home/scott/test.php(64): Robots::someMethod()
#2 {main}
40 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
PHP has a rich library of functions you can use in your extensions. To call a PHP function, you can just refer its name
in the Zephir code.
namespace MyLibrary;
class Encoder
{
You can call also functions that are expected to exist in the PHP userland but they arent built-in with PHP:
namespace MyLibrary;
class Encoder
{
Note that all PHP functions only receive and return dynamic variables, if you pass a static typed variable as a parameter,
some temporary dynamic variable will be used as a bridge in order to call them:
namespace MyLibrary;
class Encoder
{
Similarly, functions return dynamic values that cannot be directly assigned to static variables without the appropriate
cast:
namespace MyLibrary;
class Encoder
{
if strlen(text) != 0 {
let encoded = (string) base64_encode(text);
return ( . encoded . );
}
return false;
}
}
Sometimes, we would need to call functions in a dynamic way, you can call them as follows:
namespace MyLibrary;
class Encoder
{
1.15 Closures
You can use closures or anonymous functions in Zephir, these are PHP compatible and can be returned to the PHP
userland:
namespace MyLibrary;
class Functional
{
It also can be executed directly within Zephir and passed as parameter to other functions/methods:
namespace MyLibrary;
class Functional
{
42 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
class Functional
{
Most common functions in Zephir use internal optimizers. An optimizer works like an interceptor for function calls.
An optimizer replaces the call for the function in the PHP userland by direct C-calls which are faster and have a
lower overhead improving performance.
To create an optimizer you have to create a class in the optimizers directory, the following convention must be used:
Function in Zephir Optimizer Class Name Optimizer Path Function in C
calculate_pi CalculatePiOptimizer optimizers/CalculatePiOptimizer.php my_calculate_pi
This is the basic structure for an optimizer:
<?php
namespace Zephir\Optimizers\FunctionCall;
use Zephir\Call;
use Zephir\CompilerException;
use Zephir\CompilationContext;
use Zephir\Optimizers\OptimizerAbstract;
Implementation of optimizers highly depends on the kind of code you want to generate. In our example, were going
to replace the call to this function by a call to a c-function. In Zephir, the code used to call this function is:
let pi = calculate_pi(1000);
So, the optimizer will expect just one parameter, we have to validate that to avoid problems later:
<?php
if (!isset($expression[parameters])) {
throw new CompilerException("calculate_pi requires one parameter", $expression);
}
if (count($expression[parameters]) > 1) {
throw new CompilerException("calculate_pi requires one parameter", $expression);
}
//...
}
There are functions that are just called and they dont return any value, our function returns a value that is the calculated
PI value. So we need to be aware that the type of the variable used to received this calculated value is OK:
<?php
if (!isset($expression[parameters])) {
throw new CompilerException("calculate_pi requires one parameter", $expression);
}
if (count($expression[parameters]) > 1) {
throw new CompilerException("calculate_pi requires one parameter", $expression);
}
/**
* Process the expected symbol to be returned
*/
$call->processExpectedReturn($context);
$symbolVariable = $call->getSymbolVariable();
if (!$symbolVariable->isDouble()) {
throw new CompilerException("Calculated PI values only can be stored in double variables", $e
}
//...
}
Were checking if the value returned will be stored in a variable type double, if not a compiler exception is thrown.
The next thing we need to do is process the parameters passed to the function:
<?php
As a good practice with Zephir is important to create functions that dont modify their parameters, if you are changing
the parameters passed, Zephir will need to allocate memory for constants passed and you have to use getResolved-
Params instead of getReadOnlyResolvedParams.
44 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
Code returned by these methods is valid C-code that can be used in the code printer to generate the c-function call:
<?php
All optimizers must return a CompiledExpression instance, this will tell the compiler the type returned by the code
and its related C-code.
The complete optimizer code is:
<?php
namespace Zephir\Optimizers\FunctionCall;
use Zephir\Call;
use Zephir\CompilerException;
use Zephir\CompilationContext;
use Zephir\CompiledExpression;
use Zephir\Optimizers\OptimizerAbstract;
if (!isset($expression[parameters])) {
throw new CompilerException("calculate_pi requires one parameter", $expression);
}
if (count($expression[parameters]) > 1) {
throw new CompilerException("calculate_pi requires one parameter", $expression);
}
/**
* Process the expected symbol to be returned
*/
$call->processExpectedReturn($context);
$symbolVariable = $call->getSymbolVariable();
if (!$symbolVariable->isDouble()) {
throw new CompilerException("Calculated PI values only can be stored in double variables"
}
The code that implements the function my_calculate_pi is written in C and must be compiled along with the exten-
sion.
This code must be placed in the ext/ directory where you find appropiate, just check that those files do not conflict
with the files generated by Zephir.
This file must contain the Zend Engine headers and C implementation of the function:
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ext.h"
Every Zephir extension has a configuration file called config.json. This file is read by Zephir everytime you build or
generate the extension and it allows the developer to modify the extension or compiler behavior.
This file use JSON as configuration format which is very known and friendly:
{
"namespace": "test",
"name": "Test Extension",
"description": "My amazing extension",
"author": "Tony Hawk",
"version": "1.2.0"
}
Settings defined in this file override any factory default setting provided by Zephir.
The following settings are supported:
1.17.1 namespace
The namespace of the extension, it must be a simple identifier respecting the regular expression: [a-zA-Z0-9_]+:
{
"namespace": "test"
}
1.17.2 name
46 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
1.17.3 description
1.17.4 author
1.17.5 version
1.17.6 warnings
1.17.7 optimizations
1.17.8 globals
Extension globals available. Check the extension globals chapter for more information.
{
"globals": {
"my_setting_1": {
"type": "bool",
"default": true
},
"my_setting_2": {
"type": "int",
"default": 10
}
}
1.17.9 info
PHP extensions provide a way to define globals within an extension. Reading/writing globals should be faster than
any other global mechanisms (like static members). You can use extension globals to set up configuration options that
change the behavior of your library.
In Zephir, extension globals are restricted to simple scalar types like int/bool/double/char, etc. Complex types such as
string/arrays/objects/resources arent allowed here.
You can enable extension globals by adding the following structure to your config.json:
{
//...
"globals": {
"allow_some_feature": {
"type": "bool",
"default": true
},
"number_times": {
"type": "int",
"default": 10
},
"some_component.my_setting_1": {
"type": "bool",
48 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
"default": true
},
"some_component.my_setting_2": {
"type": "int",
"default": 100
}
}
}
Inside any method you can read/write extension globals using the built-in functions globals_get/globals_set:
globals_set("allow_some_feature", true);
let someFeature = globals_get("allow_some_feature");
If you want to change these globals from PHP a good option is enable a method aimed at this:
namespace Test;
class MyOptions
{
Extension globals cannot be dynamically accessed since the C-code generated by globals_get/globals_set optimizers
must be resolved at compilation time:
let myOption = "someOption";
Like most extensions, Zephir extensions are able to show information at the phpinfo() output. These information is
usually related to directives, enviroment data, etc.
By default, every Zephir extension automatically adds a basic table to the phpinfo() output showing the extension
version.
You can add more directives by adding the following configuration to the config.json file:
"info": [
{
"header": ["Directive", "Value"],
"rows": [
["setting1", "value1"],
["setting2", "value2"]
]
},
{
"header": ["Directive", "Value"],
"rows": [
["setting3", "value3"],
["setting4", "value4"]
]
}
]
Zephirs compiler provides static analysis of the compiled code. The idea behind this feature is to help the developer
to find potential problems and avoid unexpected behaviors.
50 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
Static Analysis of assignments tries to identify if a variable is used before its assigned:
class Utils
{
public function someMethod(b)
{
string a; char c;
if b == 10 {
let a = "hello";
}
The above example illustrates a common situation. The variable a is assigned only when b is equal to 10, then its
required to use the value of this variable but it could be uninitialized. Zephir detects this and automatically initializes
the variable to an empty string and generates a warning alerting the developer:
Warning: Variable a was assigned for the first time in conditional branch,
consider initialize it in its declaration in
/home/scott/test/test/utils.zep on 21 [conditional-initialization]
for c in a {
Finding such errors is sometimes tricky, however static analysis helps the programmer to find bugs in advance.
Zephir informs the developer about unreacheable branches in the code and performs dead code elimination which
means eliminate all those code from the generated binary as this cannot be executed:
class Utils
{
public function someMethod(b)
{
if false {
// This is never executed
echo "hello";
}
}
}
1.21 Optimizations
Because the code in Zephir is sometimes very high-level, a C compiler might not be in the ability to optimize this code
enough.
Zephir, thanks to its AOT compiler, is able to optimize the code at compile time potentially improving its execution
time or reducing the memory required by the program.
1.21. Optimizations 51
Zephir Documentation, Release 0.6.3
1.21.1 static-type-inference
This compilation pass is very important, since it looks for dynamic variables that can potentially transformed into
static/primitive types which are better optimized by the underlying compiler.
The following code use a set dynamic variables to perform some mathematical calculations:
public function someCalculations(var a, var b)
{
var i = 0, t = 1;
return i + b;
}
Variables a, b and i are used all of them in mathematical operations and can thus be transformed into static
variables taking advantage of other compilation passes. After this pass, the compiler automatically rewrites this code
to:
public function someCalculations(int a, int b)
{
int i = 0, t = 1;
return i + b;
}
By disabling this compilation pass, all variables will maintain the type which they were originally declared without
optimization.
1.21.2 static-type-inference-second-pass
This enables a second type inference pass which improves the work done based on the data gathered by the first static
type inference pass.
52 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
1.21.3 local-context-pass
This compilation pass moves variables that will be allocated in the heap to the stack.
1.21.4 constant-folding
Constant folding is the process of simplifying constant expressions at compile time. The following code is simplified
when this optimization is enabled:
public function getValue()
{
return (86400 * 30) / 12;
}
Is transformed into:
public function getValue()
{
return 216000;
}
1.21.5 static-constant-class-folding
Is transformed into:
class MyClass
{
1.21.6 call-gatherer-pass
This pass counts how many times a function or method is called within the same method. This allow the compiler to
introduce inline caches to avoid method or function lookups.
1.21. Optimizations 53
Zephir Documentation, Release 0.6.3
The compiler raise warnings when it finds situations where the code can be improved or a potential error can be
avoided.
Warnings can be enabled via command line parameters or can be added to the config.json to enable or disable them
permanently:
You can enable warnings by passing its name prefixed by -w:
zephir -wunused-variable -wnonexistent-function
1.22.1 unused-variable
Raised when a variable is declared but it is not used within a method. This warning is enabled by default.
public function some()
{
var e; // declared but not used
return false;
}
1.22.2 unused-variable-external
1.22.3 possible-wrong-parameter-undefined
54 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
1.22.4 nonexistent-function
1.22.5 nonexistent-class
1.22.6 non-valid-isset
Raised when the compiler detects that an isset operation is being made on a non array or object value:
public function some()
{
var b = 1.2;
return isset b[0]; // variable integer b used as array
}
1.22.7 non-array-update
Raised when the compiler detects that an array update operation is being made on a non array value:
public function some()
{
var b = 1.2;
let b[0] = true; // variable b cannot be used as array
}
1.22.8 non-valid-objectupdate
Raised when the compiler detects that an object update operation is being made on a non object:
public function some()
{
var b = 1.2;
let b->name = true; // variable b cannot be used as object
}
1.22.9 non-valid-fetch
Raised when the compiler detects that a fetch operation is being made on a non array or object value:
public function some()
{
var b = 1.2, a;
fetch a, b[0]; // variable integer b used as array
}
1.22.10 invalid-array-index
Raised when the compiler detects that an invalid array index is used:
public function some(var a)
{
var b = [];
let a[b] = true;
}
1.22.11 non-array-append
Raised when the compiler detects that an element is being tried to be appended to a non array variable:
public function some()
{
var b = false;
let b[] = "some value";
}
1.22.12 non-array-append
Raised when the compiler detects that an element is being tried to be appended to a non array variable:
public function some()
{
var b = false;
let b[] = "some value";
}
56 Chapter 1. Reference
Zephir Documentation, Release 0.6.3
1.23 License
1.23. License 57
Zephir Documentation, Release 0.6.3
58 Chapter 1. Reference
CHAPTER 2
Other Formats
59
Zephir Documentation, Release 0.6.3
I
index
index, 59
61