Documentation
Why CrowPHP?
PHP has grown a lot as a language it has a mature ecosystem and a vibrant community, for PHP to become a goto language for modern-microservices and container oriented ecosystem we lacked a way to deploy our web services in a stand-alone PHP, well not any more, with the advancements in asynchronous and concurrent PHP environment provided by platforms like SwoolePHP and ReactPHP it’s not a dream any more to run your web services on stand-alone PHP and here comes CrowPHP to provide an elegant and un-opinionated framework on top of SwoolePHP and ReactPHP HTTP servers.
Your First CrowPHP Microservice
Before we start with the crowPHP lets make sure you have the right system requirements.
- PHP-CLI version 8 or above.
- composer package manager for PHP
- PHP pear package manager
pecl
- SwoolePHP latest version
pecl install swoole
Docker Example
To follow this example I am assuming that you are familiar with docker
and docker-compose
and the latest versions are installed on your system.
Let’s start with a new composer.json
file in your project.
{
"name": "helloworld",
"authors": [
{
"name": "Your Name",
"email": "your@email.com"
}
],
"require": {
"crowphp/crow": "0.3.1"
}
}
Now let’s create a new PHP file in the root of your project index.php
. In this file, we will be created a new CrowPHP server and a route that will serve our request.
<?php
require 'vendor/autoload.php';
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface as RequestInterface;
use Crow\Http\Server\Factory as CrowServer;
$app = CrowServer::create(CrowServer::SWOOLE_SERVER);
$router = Crow\Router\Factory::make();
$router->get('/', function (RequestInterface $request, ResponseInterface $response) {
$response->getBody()->write('Hello World!');
return $response;
});
$app->withRouter($router);
$app->on('start', function ($server) {
echo "CrowPHP server is listening on port $server->host:$server->port " . PHP_EOL;
});
$app->listen(5000, "0.0.0.0");
First, we have imported the generic vendor/autoload.php
that will provide us with the resolutions of all the necessary namespaces
and classes. We are using standard PSR
request and response interfaces, which are supported by CrowPHP.
We are then creating an $app
instance from the CrowServer::create
method by passing a single integer constant CrowServer::SWOOLE_SERVER
this is important because CrowPHP also supports ReactPHP server but for this example; we are going to stick with SwoolePHP
as its more production-ready at the moment.
After that we are making a $router
instance from the router factory i.e. Crow\Router\Factory::make
, with router instance in the next step we call a get
method to create a new route which accepts to parameters i.e. {path}
and a {handler}
. Handler is a callback
function and it provides $request
and $response
instances that expect the instance of ResponseInterface
to be returned.
Now the instance of the router is attached to the main app instance with the $app->withRouter
method and we have attached a listener for the start
event just to log in when the server is ready to accept new requests.
At last, we have called the listen
method with 5000
port and 0.0.0.0
as host since we are running in the Docker container.
Docker File
Now let’s create a new Dockerfile
in the root your project with following contents, and ofcourse you can modify it to your liking :)
FROM php:8.0-cli-buster
RUN apt update && apt upgrade -y
RUN apt install zip unzip libzip-dev git -y
# Install PHP extensions
RUN pecl install swoole \
&& pecl install zip \
&& docker-php-ext-enable swoole zip
RUN mv /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini
# Install Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
WORKDIR /code
ADD entry.sh /usr/bin/entry.sh
EXPOSE 5000/tcp
ENTRYPOINT [ "/usr/bin/entry.sh" ]
If you notice we are adding a file entry.sh
in our docker file lets create that file in the root of our project.
#!/bin/bash
composer install
php index.php
It can’t be more simpler, we are installing composer when the container starts for the first time followed by execution of our PHP server.
Docker Compose File
Finally to make our project easier to manage for the next time we will be using docker-compose and this step is (optional). Let’s create a new docker-composer.yaml
file in the root of the project.
version: "3"
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
Now, we can finally run our project with docker-compose up
and our service should be ready to recieve requests on http://localhost:5000