ZealPHP is a lightweight, high-performance PHP framework that brings modern web development paradigms to PHP using OpenSwoole's asynchronous I/O capabilities. It offers features comparable to frameworks like Next.js and allows developers to build efficient web applications with PHP.
OpenSwoole enables PHP to achieve true parallelism through multi-threading and multi-processing, allowing applications to utilize multiple CPU cores effectively. It provides asynchronous, non-blocking I/O operations and implements coroutines at the C level, enabling high concurrency with minimal overhead.
In contrast, Node.js operates on a single-threaded event loop. While it handles I/O-bound tasks efficiently using asynchronous operations, it may struggle with CPU-intensive tasks without additional configuration. Node.js can use worker threads for parallel execution, but this adds complexity and is not default behavior.
Aspect | OpenSwoole (with ZealPHP) | Node.js |
---|---|---|
Parallelism | True parallelism with multiple processes/threads, solves C1000K without additional configuration | Single-threaded; parallelism via worker threads, cant solve C1000K without additional configuration |
Concurrency Model | Coroutines and event-driven architecture | Event loop with asynchronous callbacks/promises |
Performance | High performance for both I/O and CPU-bound tasks | Efficient for I/O-bound tasks; additional setup for CPU-bound tasks |
Scalability | Utilizes multiple CPU cores; scales vertically and horizontally | Scales horizontally using multiple instances |
ZealPHP doesn't load everything into memory, it does dynamic injection on demand, encouraging SSR operations with the powerful dynamic in-memory nested templating engine to support Progressive Enhancement and Graceful Degredation concepts, thus preserves the natural flow of web.
ZealPHP serves the public
folder by automatically mapping URLs to PHP files within the public
directory, enabling support for traditional PHP applications without needing explicit routes. For example, a request to /home
will serve the file public/home.php
if it exists.
By default, ZealPHP serves the public/index.php
file for the root URL. All the .php
extensions are removed from the URL. This behavior can be overrided for extended support. Applications reling on .htaccess
or nginx
URL rewriting can easily run within ZealPHP's public directory with correct routes programmed.
To define APIs, place your PHP files inside the api
directory. ZealPHP provides implicit routing for these API endpoints. For instance, the file api/test.php
defines an API endpoint at /api/test
:
<?php
// File: api/test.php
$test = function () {
// API logic here or render HTML with coroutines and async I/O and just output them to STDIO
};
To render templates, use the App::render
method to include template files from the template
directory. This allows for reusable components and layouts. In public/home.php
, you can render a master template like this:
<?php
use ZealPHP\App;
App::render('_master', [
'title' => 'ZealPHP',
'description' => 'A simple PHP framework for OpenSwoole',
]);
To start using ZealPHP, you need to install OpenSwoole and set up your development environment. ZealPHP leverages OpenSwoole to provide an asynchronous, high-performance PHP server.
# Install required packages
sudo apt install gcc php-dev openssl libssl-dev curl libcurl4-openssl-dev libpcre3-dev build-essential
sudo pecl install openswoole
During installation, enable coroutine sockets, OpenSSL support, HTTP2 protocol, coroutine MySQL, and coroutine CURL when prompted.
php.ini
:
echo "extension=openswoole.so" | sudo tee -a /etc/php/8.3/cli/conf.d/99-zealphp-swoole.ini
echo "short_open_tag=on" | sudo tee -a /etc/php/8.3/cli/conf.d/99-zealphp-swoole.ini
php -m | grep openswoole
sudo apt install composer
composer create-project --stability=dev sibidharan/zealphp-project my-project
cd my-project
composer update
php app.php
ZealPHP is designed to integrate seamlessly with OpenSwoole, allowing developers to write asynchronous PHP applications with ease. It provides a familiar development experience while leveraging the power of coroutines and asynchronous I/O.
public
and api
endpoints<?php
// File: app.php
require 'vendor/autoload.php';
use ZealPHP\App;
$app = App::init('0.0.0.0', 8080);
# Define routes here
$app->route('/hello/{name}', function($name){
echo "Hello, $name!";
});
# Additional routes can be added in `route` directory also
$app->run();
Below is an example of how additional user definded routes are defined in ZealPHP:
<?php
// In app.php or inside route directory
$app->route('/quiz/{page}', function($page) {
echo "<h1>This is quiz: $page</h1>";
});
use function ZealPHP\response_add_header;
use function ZealPHP\response_set_status;
$app->route("/suglobal/{name}", [
'methods' => ['GET', 'POST']
],function($name) {
response_add_header('X-Prototype', 'buffer');
response_set_status(202);
// $g = G::instance();
if(App::$superglobals){
if (isset($GLOBALS[$name])) {
print_r($GLOBALS[$name]);
} else{
echo "Unknown superglobal";
}
} else {
//This works both ways with, with App::superglobal(true), this will write to actual superglobal
$g = G::instance();
if (isset($g->$name)) {
print_r($g->$name);
} else{
echo "Unknown global";
}
}
});
// You can add namespaces to routes for better management
$app->nsRoute('watch', '/get/{key}', function($key){
echo $_GET[$key] ?? null; //with App::superglobal(true);
// use ZealPHP\G; # the superglobal implementation that works both ways
$g = G::instance();
$g->get['key'] = $key;
echo $g->get['key'];
});
// This is also the implicit implementation of API routes
$this->nsPathRoute('api', "{module}/{rquest}", [
'methods' => ['GET', 'POST', 'PUT', 'DELETE']
], function($module, $rquest, $response, $request){
$api = new ZealAPI($request, $response, self::$cwd);
try {
return $api->processApi($module, $rquest);
} catch (\Exception $e){
$api->die($e);
}
});
//Returning PSR Responses
$app->route("/coglobal/set/session", [
'methods' => ['GET', 'POST']
],function($name) {
//Out buffer will be ignored when returning PSR responses
echo "Hello World";
$G = G::instance();
$G->session['name'] = $name;
return new Response('Session set', 300, 'success', ['Content-Type' => 'text/plain', 'X-Test' => 'test']);
});
// Matches any URL starting with /raw/
$app->patternRoute('/raw/(?P.*)', ['methods' => ['GET']], function($rest) {
echo "You requested: $rest";
return 202; // return status code
});
# Implicit route for ignoring PHP extensions, requesting OpenSwoole response with Dynamic Injection
# In such cases, the STDIO buffer will be ignored and $response->write takes precedence
$this->patternRoute('/.*\.php', ['methods' => ['GET', 'POST']], function($response) {
$response->status(403);
$response->write("403 Forbidden");
});
# Implicit route for index.php
$this->route('/', function($response){
$g = G::instance();
$file = 'index';
$g->server['PHP_SELF'] = '/'.$file.'.php';
// Not needed since G$ writes to actual superglobal when App::superglobal(true) is set
// if(self::$superglobals){
// $_SERVER['PHP_SELF'] = $g->server['PHP_SELF'];
// }
$abs_file = self::$cwd."/public/".$file.".php";
if(file_exists($abs_file)){
include $abs_file;
} else {
//TODO: Can load user page here if file not found
echo("404 Not Found");
return(404);
}
});
Note: Implicit rules are provided with the least priority, you can override them at app.php or from route directory.
All files inside route
folder are included prior to the implicit routes letting the user override the implicit routes on demand. For example, `route/contact.php` may look like
<?php
// File: route/contact.php
use ZealPHP\App;
$app = App::instance();
$app->route('/data/{id}', function($id) {
echo "This is example api to receive ID: $id";
});
$app->route('/contact', function() {
App::render('contact');
});
All contributions are welcome. Feel free to submit issues or pull requests on GitHub to help improve ZealPHP.
For more information, visit the ZealPHP GitHub repository and explore the documentation and examples.