Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jimthunderbird/php-to-c-extension


https://github.com/jimthunderbird/php-to-c-extension

Last synced: about 2 months ago
JSON representation

Awesome Lists containing this project

README

        

PHP-TO-C-Ext is a tool to allow developer to build Zend Engine based PHP Extensions using PHP together with C.

PHP-TO-C-EXT is built on top of these great things:

+ Zephir (http://zephir-lang.com/)
+ PHP Parser (https://github.com/nikic/PHP-Parser)
+ PHP to Zephir (https://github.com/fezfez/php-to-zephir)

PHP-TO-C-EXT is tested on Fedora Linux 21 and Mac OS Yosemite From PHP 5.4 to 5.6.

##Installation

1. Install composer
2. git clone https://github.com/jimthunderbird/php-to-c-extension.git
3. cd php-to-c-extension
4. composer.phar install

##Usage:

```sh
$ php [path/to/php-to-c-extension]/build_extensions.php [php file to convert to c extension]
```

or

```sh
$ php [path/to/php-to-c-extension]/build_extensions.php [directory containing php files to convert to c extension]
```

##Examples:

+ [A simple dummy extension](#example-01)
+ [One namespace and multiple classes in one file](#example-02)
+ [Organize multiple files in one directory](#example-03)
+ [Using for loop](#example-04)
+ [Using sub-namespaces] (#example-05)
+ [Using interface] (#example-06)
+ [Using trait] (#example-07)
+ [Calling method in the base class with parent::](#example-08)
+ [Using the self keyword](#example-09)
+ [Using ternary operator](#example-10)
+ [Late static binding](#example-11)
+ [Performance Benchmark: Bubble Sort](#example-12)
+ [Gain greater speed through raw C code, using call_c_function](#example-13)
+ [Using PHP Code together with raw C code to solve problems, using call_c_function](#example-14)
+ [Better code structure and saving development time when working with raw C code, using call_c_auto](#example-15)

###Example 01

Let's create a file named Dummy.php, it looks like this:

```php
say();
```
#### and if we run it with php -c [path/to/php.ini]/php.ini test.php, we should get "hello" printed.
#### You might have already noticed, the class Hello has the namespace Dummy and the extension name is dummy.so.
#### In fact, in order to build a php extension with this tool, all classes must have a CamelCase namespace, and the extension name is the lowercase form of the namespace.

###Example 02
####Sometimes, for convenience, we might want to write a single file with one namespace and multiple classes, and we can do just that.
####Let's create a file named Dummy.php an it looks like the following:
```php
getSum(1,10);
```

###Example 05
####We can use sub namespaces to better manage the cod in the extension.
####When using sub namespaces, we need to make sure the first part of the sub namespace match is name of our extension.
####In this example, let's create a dummy extension with the following files.
####1. src/Dummy/Vehicle.php
####2. src/Dummy/Vehicle/Car.php
####src/Dummy/Vehicle.php looks like this:
```php
say();
```
####We will have "I am a vehicle" printed.

###Example 06
####We can use interface just like what we do in normal php code.
####Let's created the following files:
####1. src/Dummy/MovableInterface.php
####2. src/Dummy/Vehicle.php
####src/Dummy/MovableInterface.php looks like this:
```php
move();
```
####We will have "I am moving" printed.

###Example 07
####Trait is a new feature introduced in php 5.4 to allow grouping of functionalities and reused by individual classes.
####In the example below, we are going to demonstrate using trait to build a dummy php extension
####We are going to create a file src/dummy.php, and it looks like this:
```php
play();
$vehicle->move();
```
####We will see the "I am playing.I am moving." printed

###Example 08
####When we need to call certain methods in the base class, we will need to use the parent keyword, below is an example:
####Let's create a file named dummy.php and it looks like this:
```php
stop();
```
####We should see the following printed
####"I am a new vehicle.I am also a new car.I am stopping now.don't worry i am a car."

###Example 09
####We can use the self keyword just like normal php to build a php extension, below is an example:
####Let's create a file named dummy.php and it looks like this:
```php
stop()."\n";
```
####We should see the following printed
####"I am a new vehicle.Two cars are identical
####I am stopping now."

###Example 10
####We can use ternary operator as a shortcut to write conditional statemements and variable assignmens
####Let's create a file named dummy.php and it looks like this:
```php
number = $number;
}

public function isPositive()
{
$result = ($this->number > 0)?true:false;
return $result;
}
}
```
####Then once we dummy.so built, in the user code if we do the following:
```php
isPositive() === TRUE) {
echo "This is a positive number.";
}
```
####We then should see the following printed on the screen.
####"This is a positive number."

###Example 11
####Late static binding is introduced in PHP 5.3 and used to reference the called class in a context of static inheritance.
####Below is an example of late static binding
####Let's create a file named src/dummy.php and it looks like this:
```php
namespace Dummy;
class Model
{
protected static $name = "model";
public static function find()
{
echo static::$name;
}
}

class Product extends Model
{
protected static $name = 'Product';
}
```
####Then once we have dummy.so built and if we do the following:
```php
Dummy\Product::find();
```
####We should have "Product" printed on the screen.

###Example 12
####Below let's do a simple benchmark to see how fast the php extension will be
####We will be using bubble sort as an example to demonstrate the time difference. Here is our code for src/dummy.php:
```php
= 1; $i--) {
$arr[] = $i;
}

$time_start = microtime_float();

$st = new Dummy\Sorter();
$arr = $st->bubbleSort($arr);

$time_end = microtime_float();
$time = $time_end - $time_start;

print "Time spent on sorting: ".$time." seconds.\n";
```
####The code above is pretty straightforward, it first detect if we have the Dummy\Sorter class defined, if it is defined, that means the dummy.so extension is loaded, otherwise, we will just require the pure php version of Dummy\Sorter class.
####We then generate an array of 10000 integers and ask Dummy\Sorter to bubble sort it.
####This is also the beauty of having the ability to write our extension in php itself, since we can seamlessly compare the performance.
####Now if we just do:
```sh
php test.php
```
####We will be just using the pure php version, in my intel core i3 laptop with 4 core cpu running fedora 21 and PHP 5.6.4, it shows the following:
####Time spent on sorting: 16.802139997482 seconds.
####Now let's test the php extension see how it performs. We first create php.ini and then inside we have:
```sh
extension=dummy.so
```
####Then if we do php -c php.ini test.php, we will be using the dummy.so to do the bubble sort for us, in my laptop it shows the following:
####Time spent on sorting: 3.9628620147705 seconds.
####As you can see, the php extension dummy.so that we built is about 3 times faster than the pure php version. And we are seamlessly using the same Dummy\Sorter class!

###Example 13
####PHP is built on top of Zend Engine, which is written in C. It will be great that we could use C code inside PHP to gain higher performance.
####In this tool, we have a way to do so, by using the call_c_function api.
####In the example below, we will be using the call_c_function api to call the C based bubble sort implementation from within PHP.
####This example requires advance knowledge of the internal data structure of the Zend Engine.
####First, let's create src/dummy.php
```php
value.ht;
long arr_length = arr_hash->nNumOfElements;
long i,j;

zval **p;

long sorting_arr[arr_length];
long tmp;

for (i=0; i < arr_length; i++) {
p = (zval **)(arr_hash->arBuckets[i]->pData);
sorting_arr[i] = (*p)->value.lval;
}

//perform bubble sort
for (i=0; i< arr_length; i++) {
for (j=0; j= 1; $i--) {
$arr[] = $i;
}

$time_start = microtime_float();

$st = new Dummy\Sorter();
$arr = $st->bubbleSort($arr);

$time_end = microtime_float();
$time = $time_end - $time_start;

print "Time spent on sorting: ".$time." seconds.\n";
```
####Now if we add extension=dummy.so to a php.ini file and do
```sh
$ php -c php.ini test.php
```
####We will see the following printed on the screen
####Time spent on sorting: 0.14397192001343 seconds.
####The result is really great. Compared to 3.9628620147705 seconds in example 12 and 16.802139997482 seconds for the pure PHP version, it is significantly faster.

###Example 14
####In this example below, we will be using PHP code together with raw C code to get the first 800 digits of PI.
####The algorithm to compute PI is borrowed from https://crypto.stanford.edu/pbc/notes/pi/code.html
####First, we will be creating the src/dummy.php and it looks like this:
```php
0; k -= 14) {
d = 0;

i = k;
for (;;) {
d += r[i] * 10000;
b = 2 * i - 1;

r[i] = d % b;
d /= b;
i--;
if (i == 0) break;
d *= i;
}

sprintf(tmp_buf, "%.4d", c + d / 10000);

buf[count] = tmp_buf[0];
buf[count+1] = tmp_buf[1];
buf[count+2] = tmp_buf[2];
buf[count+3] = tmp_buf[3];

c = d % 10000;

count += 4;
}

buf[count+1] = '\0';

ZVAL_STRING(result, buf, 1);

return result;
}
```
####Then we will have test.php
```php
getPI();
```
####Then once dummy.so is built and we do:
```sh
$ php -c php.ini test.php
```
####We will be seeing the first 800 digits of PI printed on the screen.

###Example 15
####In example 13 and 14 above, we demonstrate the ability to work with PHP and raw C code to solve problems.
####One thing that came up is, if we are developing on a large extension codebase, using call_c_function and specifying the C source file name and C function name is a bit time consuming and at some points might become tedious. This is when the API call_c_auto comes into help.
####Below we will demonstrate using call_c_auto to do bubble sort.
####Let's first create file src/Dummy/Sorter.php:
```php
0) {
$result = call_c_auto($arr);
}
return $result;
}
}
```
####Notice this line here:
```php
$result = call_c_auto($arr);
```
####What we are doing is to pass the $arr input param to the call_c_auto API. Under the hook the extension building process will convert this API to:
```php
$result = call_c_function("Sorter.c","bubbleSort",$arr);
```
####See the Sorter.c has the same name as the class name Sorter, and the C function we will be calling has the same name as the PHP method name bubbleSort.
####This convention helps us organize the code better and save some typing.
####Now let's create src/Dummy/Sorter.c
```php
static zval * bubbleSort(zval * arr)
{
HashTable *arr_hash = arr->value.ht;
long arr_length = arr_hash->nNumOfElements;
long i,j;

zval **p;

long sorting_arr[arr_length];
long tmp;

for (i=0; i < arr_length; i++) {
p = (zval **)(arr_hash->arBuckets[i]->pData);
sorting_arr[i] = (*p)->value.lval;
}

//perform bubble sort
for (i=0; i< arr_length; i++) {
for (j=0; jbubbleSort($arr);

print_r($arr);
```
####And let's build our extension by doing:
```sh
$ php [path/to/php-to-c-extension]/build_extensions.php src/Dummy
```
####Then once dummy.so is built and we add extension=dummy.so to php.ini, we can run our test code:
```sh
$php -c php.ini test.php
```
####And we will see that our array is nicely sorted.
####The advantage of using call_c_auto in this example is, we have src/Dummy/Sorter.php and src/Dummy/Sorter.c and they interact nicely to solve our problem.