Hello world ᴾᴴᴾ - chung-leong/zigar GitHub Wiki

JavaScript | PHP


In this example we're going to create a very simple server-side app that outputs "Hello world!" to the console through Zig. It demonstrates the basics of working with php-zigar and the steps for deploying an app in different server environments.

Make sure you have activate the php-zigar extension in php.ini before you begin.

Creating the sample app

First, create an new directory for the project:

mkdir hello

Create one directory for PHP files and another for Zig files:

cd hello
mkdir src zig

In a text editor, create hello.zig in zig:

const std = @import("std");

pub fn hello() void {
    std.debug.print("Hello world!", .{});
}

Followed by hello.php in src:

<?php

$m = zigar_use(__DIR__ . '/../zig/hello.zig');

$m->hello();

Then run it:

php src/hello.php

A message will appear informing you that the module "hello" is being built. After 30 seconds or so, the following should appear in the terminal:

Hello world!

At this point, you'll notice that a lib sub-directory has been added to hello. Within it, you'll see a sub-directory named hello.zigar. This is the Zigar module. The directory can contain multiple dynamically linked libraries, each targetting a specific platform. For now, you'll only see the one created for your computer, either linux.x64.so or win32.x64.dll.

When zigar_use() is given a path to a zig file, it'll both compile and load the module. The setting zigar.module_rel_path determines where the module will be placed relative to the source file. By default it's /../lib.

You can use zigar_compile() to create the module at an abitrary location:

<?php

zigar_compile(__DIR__ . '/../zig/hello.zig', '/tmp/zig-stuff/turkey');
$m = zigar_use('/tmp/zig-stuff/turkey');

$m->hello();

Importing functions and classes

zigar_use() keeps Zig functions and classes within the object that it returns. You can make these functions and classes appear in the global PHP namespace by using zigar_import() instead:

<?php

$m = zigar_import(__DIR__ . '/../zig/hello.zig');

$m->hello();
hello();
Hello world!
Hello world!

Doing so will prevent the module from getting garbage-collected until the request finishes.

zigar_import() accepts a callback function as its second argument which allows you to customize the names of the imported symbols:

<?php

$m = zigar_import(__DIR__ . '/../zig/hello.zig', function($name, $type) {
    return "cow_{$name}_${type}";
});

cow_hello_function();

Configuring the app for deployment

If you're a Windows or Mac user, shared libraries created during development will most likely not work in your eventual production environment. Moreover, they're compiled at the Debug optimization level, meaning they are both slow and needlessly large. To make the module a production-ready module, you need a build script.

In your editor, create build.php in src:

<?php

$targets = [
    [ 'platform' => 'linux', 'arch' => 'x64' ],
    [ 'platform' => 'linux', 'arch' => 'arm64' ],
    [ 'platform' => 'darwin', 'arch' => 'arm64' ],
    [ 'platform' => 'win32', 'arch' => 'x64' ],
];
foreach ($targets as $options) {
    zigar_compile(__DIR__ . '/../zig/hello.zig', $options);
}

Note: possible values for platform and arch are listed in the documentation for Node.js's os.platform() and os.arch().

Before you run the script, open php.ini and change the optimization setting:

[zigar]
zigar.optimize=ReleaseSmall

You can also specify the optimization level in the options array passed to zigar_compile(). Setting it in php.ini ensures that you wouldn't unintentionally overwrite the production-ready library with a debug version.

After build.php is done running, the directory structure of hello should look like this:

📁 hello
  📁 lib
    📁 hello.zigar
      📑 darwin.arm64.dynlib
      📑 linux.arm64.so
      📑 linux.x64.so
      📑 win32.x64.dll
      📑 win32.x64.pdb
  📁 src
  📁 zig

The module is now ready to be used in nearly any production environment. Provided, of course, that php-zigar is installed on the server.

The server's copy of php.ini should contain the following:

[zigar]
zigar.recompile=Off

This will stop php-zigar from attempting to recompile the module.

Source code

You can find the complete source code for this example here.

Conclusion

You have just learned the basics of using php-zigar in server-side applications. The app we created doesn't do much. In the next example we're going to create an app that actually does something useful.


City-Hash example