Can PHP Be Even Faster? Light-Speed with the Blink Framework

Share this article

Lumen, Silex, Slim, etc. you’ve heard of all of them. In this article, we’ll take a look at a newcomer called Blink.

Abstract image representing speed

Blink was built to improve high performance applications that consume a lot of server resources, and it uses the Swoole PHP extension to achieve this goal. As an example, we will build a Blink powered notejam for our demo. Let’s get started.

Installing the Swoole PHP Extension

We mentioned earlier that Blink relies on the Swoole extension for better performance.

You can install the Swoole extension from source on Github. Follow this article if you don’t know how to do it.

The alternative way to install it is by using the PEAR package manager, which is the approach I’ll take. I will be using an Ubuntu 14.04 image with the LAMP setup for this article, configured via Vaprobash – to get this exact setup, refer to the Vagrantfile in this project’s final repo. We could’ve used Homestead improved to easily set up the environment, but the Swoole extension is only compatible with PHP 5 for now, and Homestead Improved uses PHP 7 by default.

# update repositories
sudo apt-get update 

# Install pear manager
sudo apt-get install php-pear

# PHP source to compile the extension
sudo apt-get install php5-dev

# Used to install package dependencies
sudo apt-get install libcurl3-openssl-dev

# Installing Swoole
sudo pecl install swoole

The current Swoole version is 1.7.22-alpha and it’s not compatible with PHP 7, but there is an ongoing effort to make this happen in the next minor version.

After the commands above execute, we’re asked to add the extension=swoole.so line to php.ini. You can make sure that the extension is loaded by listing the available PHP modules command.

php -m | grep 'swoole'

Blink is available on Packagist, so we can use Composer to create a new project.

composer create-project --prefer-dist blink/seed

After all the dependencies have been loaded, you can run the server from the command line.

php blink server serve

This command will run an interactive shell for logs. However, you may use the php blink server start/stop/restart commands to manage the server.

We can make sure that everything is working as expected by visiting port 7788 of our local server:

Hello world

Configuration

While Blink doesn’t provide an option from the command line to specify the port, we can use the config/server.php file to change it.

// src/config/server.php

<?php
return [
    'class' => '\blink\server\SwServer',
    'bootstrap' => require __DIR__ . '/../bootstrap.php',
    'host' => '0.0.0.0',
    'port' => 8080,
];

Now, restart your server and check the browser using the new port. The config folder also holds configuration for our app and services.

Building the Notejam App

The Notejam application doesn’t contain a lot of functionality. You can check out the final app on Github. It offers:

  • A sign in page with the forgot password option.
  • A sign up page.
  • Account settings. (change user password)
  • Managing notes.
  • Managing pads.

Installing a Template Engine

Blink doesn’t provide a templating engine by default, we need to choose and inject our own. I chose to work with Twig, but you can easily switch to another engine like Blade, Smarty, etc. The src/bootstrap.php file is responsible for registering our routes, services and executing our application, and we will use it to bind the Twig engine to the application container.

// src/bootstrap.php

// ...
$app = new blink\core\Application($config);

require __DIR__.'/bindings.php';

return $app;
// src/bindings.php

<?php

/*
    Registering Twig
 */

$app->bind('twig.loader', function () {
    $view_paths = __DIR__.'/views';
    $loader = new \Twig_Loader_Filesystem($view_paths);

    return $loader;
});

$app->bind('twig', function () use($app) {
    $options = [
        'debug' => false,
        'cache' => __DIR__.'/../cache/views/compiled'
    ];

    $twig = new \Twig_Environment($app->get('twig.loader'), $options);

    // register Twig Extensions
    $twig->addExtension(new \Twig_Extension_Debug());

    // register Twig globals
    $twig->addGlobal('app', $app);

    return $twig;
});

Blink uses the Yii container for dependency injection. It has constructor and method injection, auto resolving for dependencies, etc. Check the documentation for more details.

Installing a Database Manager

The Notejam application requires database access for managing users, notes and pads. We’re going to use the Eloquent package for that, so we need to require it using Composer.

composer require illuminate/database 5.1.*
composer require illuminate/console 5.1.*
composer require illuminate/filesystem 5.1.*

We also required the console and filesystem packages to use database migrations to build our database.

// src/bindings.php

// ...

/*
    Registering Eloquent DB Manager
*/

use Illuminate\Database\Capsule\Manager as Capsule;

$capsule = new Capsule;
$capsule->addConnection(require __DIR__.'/config/database.php');

$app->bind('capsule', $capsule);
$capsule->setAsGlobal();
$capsule->bootEloquent();
// src/console/MigrateCommand.php

class MigrateCommand extends Command
{

    public $name = 'migrate';

    public $description = 'Migrate Database.';

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $capsule = app('capsule');
        $connectionResolver = $capsule->getDatabaseManager();
        $repository = new DatabaseMigrationRepository($connectionResolver, 'migrations');
        if( !$repository->repositoryExists() )
        {
            $repository->createRepository();
        }

        $migrator = new Migrator($repository, $connectionResolver, new Filesystem);
        
        return $migrator->run(__DIR__.'/../database/migrations');
    }
}
// src/config/app.php

<?php
return [
    // ...
    
    'commands' => [
        'App\Console\MigrateCommand',
    ]
];

After registering our command, we can run php blink migrate to create our database.

// src/database/migrations/2015_11_14_00_create_users_table.php

class CreateUsersTable extends Migration {
    public function up()
    {
       Capsule::schema()->create('users', function(Blueprint $table) {
            $table->increments('id');
            $table->string('email');
            $table->string('password', 60);
            $table->string('remember_token', 100)->nullable();
            $table->timestamps();
        });
    }

    public function down()
    {
        Capsule::schema()->drop('users');
    }
}
// src/database/migrations/2015_11_14_00_create_notes_table.php

class CreateNotesTable extends Migration {
    public function up()
    {
        Capsule::schema()->create('notes', function(Blueprint $table) {
            $table->increments('id');
            $table->string('name', 255);
            $table->text('text');
            $table->integer('user_id');
            $table->integer('pad_id')->nullable();
            $table->timestamps();
        });
    }

    public function down()
    {
        Capsule::schema()->drop('notes');
    }
}
// src/database/migrations/2015_11_14_00_create_pads_table.php

class CreatePadsTable extends Migration {
    public function up()
    {
        Capsule::schema()->create('pads', function(Blueprint $table) {
            $table->increments('id');
            $table->string('name', 255);
            $table->integer('user_id');
            $table->timestamps();
        });
    }

    public function down()
    {
        Capsule::schema()->drop('pads');
    }
}

Routes

Application routes are registered inside http/routes.php, and should return an array containing our routes definitions.

// src/http/routes.php

return [
    ['GET', '/signin', '\\App\\Http\\Controllers\\UserController@signin']
];

The first item in the array should define the request method. This could be a single item or an array to handle multiple request methods. The second item defines the request URL, and can contain rules for parameters.

// src/http/routes.php

return [
    ['GET', '/notes/{id}', '\\App\\Http\\Controllers\\NoteController@show']
];

// You can also use regex to filter parameters.

return [
    ['GET', '/notes/{id:\d+}', '\\App\\Http\\Controllers\\NoteController@show']
];

The third item specifies the request handler. This could be a Closure or a class name like the example above. Check the routes documentation for more details. Our full routes file looks like this.

// src/http/routes.php

return [
    ['GET', '/', function(blink\http\Response $response){
        return $response->redirect('/signin');
    }],

    // authentication
    ['GET', '/signin', 'UserController@signin'],
    ['POST', '/signin', 'UserController@processSignin'],

    ['GET', '/signup', 'UserController@signup'],
    ['POST', '/signup', 'UserController@store'],

    ['GET', '/logout', 'UserController@logout'],

    ['GET', '/settings', 'UserController@settings'],
    ['POST', '/settings', 'UserController@updateSettings'],

    //pads
    ['GET', '/pads', 'PadController@index'],
    ['GET', '/pads/{id:\d+}', 'PadController@show'],

    ['GET', '/pads/create', 'PadController@create'],
    ['POST', '/pads/create', 'PadController@store'],

    ['GET', '/pads/{id:\d+}/update', 'PadController@edit'],
    ['POST', '/pads/{id:\d+}/update', 'PadController@update'],

    ['GET', '/pads/{id:\d+}/delete', 'PadController@delete'],

    // Notes
    ['GET', '/notes', 'NoteController@index'],
    ['GET', '/notes/{id:\d+}', 'NoteController@show'],

    ['GET', '/notes/create', 'NoteController@create'],
    ['POST', '/notes/create', 'NoteController@store'],

    ['GET', '/notes/{id:\d+}/update', 'NoteController@edit'],
    ['POST', '/notes/{id:\d+}/update', 'NoteController@update'],

    ['GET', '/notes/{id:\d+}/delete', 'NoteController@delete'],
];

Controllers

Controllers are stored inside src/http/controllers, and you can avoid using the fully qualified namespace of your class if you store them there. However, you can use another path and change it inside the src/config/app.php file.

// src/config/app.php

<?php
return [
    // ...
    'controllerNamespace' => '\app\http\controllers',
];
// src/http/routes.php

return [
    ['GET', '/notes/{id}', 'NoteController@show'] // without a namespace
];

Sign Up

The Notejam application provides the HTML templates to be used, and we’re just going to convert them to Twig templates.

// src/views/user/signup.htm

{% extends 'layouts/layout.htm' %}

{% block page_title %}Sign Up{% endblock %}

{% block content %}
    <form action="/signup" method="POST" class="offset-by-six">
        <label for="email">E-mail</label>
        <input type="email" id="email" name="email" value="{{ oldInputs.email }}" />

        <label for="password">Password</label>
        <input type="password" id="password" name="password" value="" />

        <label for="password_confirmation">Password Confirmation</label>
        <input type="password" id="password_confirmation" name="password_confirmation" value="" />

        <input type="submit" value="Sign up" /> or <a href="/signin">Sign in</a>
    </form>
{% endblock %}

We’re extending the master layout that defines the common page structure including our page header and the errors partial.

// src/views/partials/errors.htm

{% set session = app.get('request').session %}

{% if session.get('success') or session.get('errors') %}
    <div class="alert-area">
        {% if session.get('success') %}
            <div class="alert alert-success">{{ session.get('success') }}</div>
        {% endif %}
        {% if session.get('errors') %}
            <div class="alert alert-error">
                {% for error in session.get('errors') %}
                    <ul class="errorlist">
                        <li>{{ error }}</li>
                    </ul>
                {% endfor %}
            </div>
        {% endif %}
    </div>
{% endif %}

We have access to the app container instance because we registered it as a global variable inside the Twig instance.

Our sign up form contains an email, password and a password confirmation field. Now we need to render our page.

// src/http/controllers/UserController.php

class UserController extends Object
{
    // ...
    
    public function signup()
    {
        return app()->twig->render('user/signup.htm');
    }
}

Sign up page

We handle the form submission inside our UserController@store method, and because we’ll need some validation logic, we can use the Illuminate/Validation component. So, let’s bind it to the container using our src/bindings.php file.

// src/bindings.php

// ...
/*
    Registering Validator
 */

use Illuminate\Container\Container;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Translation\FileLoader;
use Illuminate\Translation\Translator;
use Illuminate\Validation\Factory;
use Illuminate\Validation\DatabasePresenceVerifier;

$loader = new FileLoader(new Filesystem, __DIR__.'/lang');
$translator = new Translator($loader, 'en');
$validation = new Factory($translator, new Container);
$validation->setPresenceVerifier(new DatabasePresenceVerifier(app('capsule')->getDatabaseManager()));
$app->bind('validation', $validation);

The setPresenceVerifier method is useful in this case because we’ll be using the unique validation rule, which tests for the existence of the element in the database.

// src/http/controllers/UserController.php

class UserController extends Object
{
    // ...
    public function store(Request $request, Hash $hash)
    {
        $rules = [
            'email'     => 'required|email|unique:users',
            'password'  => 'required|confirmed|min:8'
        ];

        $validator = app('validation')->make($request->all(), $rules);
        if ( $validator->fails() )
        {
            $request->session->add([
                'errors' => $validator->errors()->all(),
            ]);
            
            return app('twig')->render('user/signup.htm', [
                'oldInputs'     => $request->all()
            ]);
        }

        $user = new \App\Models\User;
        $user->email = $request->body->get('email');
        $user->password = $hash->make($request->body->get('password'));
        $user->save();
        
        $request->session->add(['success' => "Welcome to Notejam, you can now log in."]);

        return $response->redirect('/signin');
    }
}

Blink supports method injection, so we can just pass our classes as a parameter and they’ll be automatically resolved for us. After building the validation rules, if anything fails we return with old inputs. The $request->session object holds our current session instance, and this is where we store our success and error messages to be displayed by the errors partial.

Sessions &Amp; Cookies

Using PHP sessions, cookies and header functions won’t work, but we can access them from the request object ($request->getSession()). Note that this could be a problem for other packages you may want to install into your project.

Sign In

Before logging users in, we need to configure our authorization component.

// src/config/services.php

// ...
'auth' => [
        'class' => 'blink\auth\Auth',
        'model' => 'App\Models\User',
    ],
// ...

The next step is to update our User model and fill the Authenticatable interface methods.

// src/models/User.php

class User extends Model implements Authenticatable
{
    protected $table = 'users';
    
    public static function findIdentity($id)
    {
        if (is_numeric($id) || (is_array($id) && isset($id['id']))) {
            return static::where('id', $id)->first();
        } else if (is_string($id) || (is_array($id) && isset($id['email'])) ) {
            return static::where('email', $id)->first();
        } else {
            throw new \InvalidParamException("The param: id is invalid.");
        }
    }

    public function getAuthId()
    {
        return $this->id;
    }

    public function validatePassword($password)
    {
        return (new Hash)->check($password, $this->password);
    }
}

The findIdentity method will be used to authenticate users using the primary key or email, and validatePassword will test the login password against the current user instance.

// src/views/user/signin.htm

{% extends 'layouts/layout.htm' %}

{% block page_title %}Sign In{% endblock %}

{% block content %}
    <form action="/signin" method="POST" class="offset-by-six">
        <label for="email">E-mail</label>
        <input type="email" value="{{ oldInputs.email }}" name="email" id="email" />

        <label for="email">Password</label>
        <input type="password" value="" name="password" id="password" />

        <input type="submit" value="Sign in" /> or <a href="/signup">Sign up</a>
        <hr />
        <p><a class="small-red" href="/forgot_password">Forgot Password?</a></p>
    </form>
{% endblock %}

Sign in page

// src/controllers/UserController.php

class UserController extends Object
{
    // ...
    public function processSignin(Request $request, Hash $hash)
    {
        $rules = [
            'email'     => 'required|email',
            'password'  => 'required|min:8'
        ];
        $validator = app('validation')->make($request->all(), $rules);
        if ( $validator->fails() )
        {
            $request->session->add([
                'errors' => $validator->errors()->all(),
            ]);

            return app('twig')->render('user/signin.htm', [
                'oldInputs'     => $request->all()
            ]);
        }

        $user = auth()->attempt($request->only(['email', 'password']));

        if ( !$user )
        {
            $request->session->add([
                'errors' => ['Login error.'],
            ]);

            return app('twig')->render('user/signin.htm', [
                'oldInputs'     => $request->all()
            ]);
        }
        
        $cookies = $response->getCookies()->add( new \blink\http\Cookie([
            'name' => 'SESSIONID', 
            'value' => $request->session->id
        ]) );

        return $response->redirect('/settings');
    }
}

We validate inputs the same way and display errors in case of failure. The auth() helper will resolve the blink/auth/Auth instance from the container, and we attempt logging the user in with the request credentials. If the login credentials are correct, we redirect the user to the settings page. Blink doesn’t manage our session automatically, so we need to set the session cookie on login and set it on the request on page load. Blink allow us to bind our services to the container using a configuration array.

// src/config/services.php

return [
    'request' => [
        'class' => \blink\http\Request::class,
        'middleware' => [\App\Http\Middleware\AuthMiddleware::class],
        'sessionKey' => function (\blink\http\Request $request) {
                $cookie = $request->cookies->get('SESSIONID');
                if ($cookie) {
                    return $cookie->value;
                }
        }
    ],
    // ...
];

Blink uses Yii’s configuration concept to initialize class attributes. We use a closure function to initialize the sessionKey using the cookie variable if it exists.

After a successful login attempt, we can access the logged in user from the request object using $request->user() and $request->guest(). Check the documentation for more details about authentication.

Account Settings

The logged in user has the ability to change his password. He must enter the old password, the new password and a confirmation. We follow the same steps as before.

// src/http/controllers/UserController.php

class UserController extends Object
{
    public function updateSettings(Request $request, Hash $hash)
    {
        $user = $request->user();
        $rules = [
            'old_password'   => 'required|min:8',
            'password'      => 'required|confirmed|min:8'
        ];

        $validator = app('validation')->make($request->all(), $rules);
        if ( $validator->fails() )
        {
            $request->session->add([
                'errors' => $validator->errors()->all(),
            ]);

            return app('twig')->render('user/settings.htm', [
                'oldInputs'     => $request->all()
            ]);
        }

        if( !$hash->check($request->input('old_password'), $user->password) )
        {
            $request->session->add([
                'errors' => ['Old password incorrect.'],
            ]);

            return app('twig')->render('user/settings.htm', [
                'oldInputs'     => $request->all()
            ]);
        }

        $user->password = $hash->make($request->input('old_password'));
        $user->save();

        $request->session->add([
                'success' => 'settings updated successfuly.',
        ]);

        return app('twig')->render('user/settings.htm');
    }
}

The $hash->check method compares a value with a hashed version. After updating the user settings we return with a success message. The problem here is that we are accessing the $request->user() method directly which returns the currently logged in user, but what if the user is not logged in yet and tries to access the settings page?

Account settings page

Middleware

To guard our routes we can define a list of middleware to our request object. We can do that inside our services.php config file.

// config/services.php

return [
    'request' => [
        'class' => \blink\http\Request::class,
        'middleware' => [\App\Http\Middleware\AuthMiddleware::class],
        'sessionKey' => function (\blink\http\Request $request) {
                $cookie = $request->cookies->get('SESSIONID');
                if ($cookie) {
                    return $cookie->value;
                }
        }
    ],
    // ...
];

Now we need to create our AuthMiddleware inside the src/http/middleware folder. The middleware will intercept all the requests, and we should compare the current request with our guarded routes.

// src/http/middleware/AuthMiddleware.php

class AuthMiddleWare implements MiddlewareContract
{
    public function handle($request)
    {
        $guardedRoutes = [
            '/\/settings/',
            '/\/logout/',
            '/\/notes?\/*.*/',
            '/\/pads?\/*.*/',
        ];

        if ( !$request->user() )
        {
            foreach ($guardedRoutes as $route)
            {
                if ( $request->match($route) )
                {
                    return response()->redirect('/signin');
                }
            }
        }

        if ( $request->user() && in_array($request->path, ['/signin', '/signup']))
        {
            return response()->redirect('/settings');
        }

    }
}

The Request@match method tests the current request path against a regular expression. It uses the PHP preg_match function, so we need to define our guarded routes as regular expressions.
If the user is not logged in and tries to access one of the guarded routes, we redirect them to the sign in page. We also want to prevent the user from accessing the signin and signup pages when they are logged in.

You can also use the before and after methods inside the controller to achieve the same result.

// src/http/controllers/UserController.php

class UserController extends Object
{
    public function before($action, $request)
    {
        // do something
    }

    public function after($action, $request, $response)
    {
        // do something
    }
}

If you noticed, in the services file, the response object also has middleware. It can be used to intercept the response object and add some information to the response, or act as a response formatter.

List Notes

The NoteController class is responsible for handling our notes’ CRUD operations.

// src/http/controllers/NoteController.php

class NoteController extends Object
{
    public function index(Request $request, Note $noteModel)
    {
        $notes = $noteModel
                    ->where('user_id', $request->user()->id)
                    ->with('pad')
                    ->get();

        return app('twig')->render('notes/index.htm', [
            'notes' => $notes
        ]);
    }
}

Because Blink supports method injection, we pass the Request and Note objects and query the user notes.

// src/views/notes/index.htm

{% extends 'layouts/layout.htm' %}

{% block page_title %}My Notes{% endblock %}

{% block content %}
    {% if notes|length %}
        <table class="notes">
            <tr>
                <th class="note">Note</th>
                <th>Pad</th>
                <th class="date">Last modified</th>
            </tr>
            {% for note in notes %}
                <tr>
                    <td><a href="/notes/{{ note.id }}">{{ note.name }}</a></td>
                    <td class="pad">
                        {% if note.pad is defined %}
                            <a href="/pads/{{ note.pad.id }}">{{ note.pad.name }}</a>
                        {% else %}
                            No pad
                        {% endif %}
                    </td>
                    <td class="hidden-text date">{{ note.updated_at|date("F jS \\a\\t g:ia") }}</td>
                </tr>
            {% endfor %}
        </table>
    {% else %}
        <p class="empty">Create your first note.</p>
    {% endif %}
    <a href="/notes/create" class="button">New note</a>
{% endblock %}

List notes page

View Note

A logged in user can only view his own notes and manage them. And because we’ll need to often check for this condition, we’re going to put it in a separate method.

// src/http/controllers/NoteController.php

class NoteController extends Object
{

    protected function noteExists( $noteId )
    {
        $request = request();
        $note = Note::with('pad')
                    ->where('user_id', $request->user()->id)
                    ->where('id', $noteId)
                    ->first();
        if( !$note )
        {
            $request->session->add([
                'errors' => ["Note not found."],
            ]);

            return false;
        }

        return $note;
    }
    // ...
}
// src/http/controllers/NoteController.php

class NoteController extends Object
{
    public function show($id, Request $request, Response $response, Note $noteModel)
    {
        $note = $this->noteExists($id);

        if( !$note )
        {
            return $response->redirect('/notes');
        }

        return app()->twig->render('notes/view.htm', [
            'note' => $note
        ]);
    }
}
// src/views/notes/view.htm

{% extends 'layouts/layout.htm' %}

{% block page_title %}{{ note.name }}{% endblock %}

{% block content %}
    <p class="hidden-text">Last edited at {{ note.updated_at|date("F jS \\a\\t g:ia") }}</p>
    <div class="note">
        <p>
            {{ note.text }}
        </p>
    </div>
    <a href="/notes/{{ note.id }}/update" class="button">Edit</a>
    <a href="/notes/{{ note.id }}/delete" class="delete-note">Delete it</a>
{% endblock %}

View note page

New Note

The new note view has a name, a text, and a pad input.

// src/views/notes/create.htm

{% extends 'layouts/layout.htm' %}

{% block page_title %}New Note{% endblock %}

{% block content %}
    <form action="/notes/create" method="POST">
        <label for="name">Name</label>
        <input type="text" id="name" name="name" value="{{ oldInputs.name }}"/>
        
        <label for="text">Text</label>
        <textarea id="text" name="text" value="{{ oldInputs.text }}"></textarea>

        <label for="pad">Pad</label>
        <select id="pad" name="pad">
            {% for pad in pads %}
                <option value="{{ pad.id }}">{{ pad.name }}</option>
            {% endfor %}
        </select>

        <input type="submit" value="Create" />
    </form>
{% endblock %}
// src/http/controllers/NoteController.php

class NoteController extends Object
{
    public function create(Request $request, Pad $padModel)
    {
        $pads = $padModel->where('user_id', $request->user()->id)->get();

        return app('twig')->render('notes/create.htm', [
            'pads' => $pads
        ]);
    }
}

New note page

Because we already set up our model relations, we can also do something like $request->user()->pads. The store method handles the form submission.

// src/http/controllers/NoteController.php

class NoteController extends Object
{
    public function store(Request $request, Response $response)
    {
        $rules = [
            'name'  => 'required',
            'text'  => 'required',
            'pad'   => 'required|exists:pads,id'
        ];
        $validator = app('validation')->make($request->all(), $rules);
        
        if ( $validator->fails() )
        {
            $request->session->add([
                'errors' => $validator->errors()->all(),
            ]);
            
            return app('twig')->render('notes/create.htm', [
                'oldInputs' => $request->all()
            ]);
        }

        $note = new Note;
        $note->name = $request->input('name');
        $note->text = $request->input('text');
        $note->user_id = $request->user()->id;
        $note->pad_id = $request->input('pad');
        $note->save();

        $request->session->add([
            'success' => 'Note saved successfully.',
        ]);

        return $response->redirect("/notes/{$note->id}/update");
    }
}

We follow the same process of validating data and returning errors in case of messages. To avoid pasting repetitive tasks for updating, deleting, and viewing notes you can check the final result on Github. The repository also contains the installation steps.

Final Notes

Although Swoole and Blink try to economize server resources by keeping your application resources alive through the application’s lifetime, the request and response objects are always refreshed on every request. Blink provides a ShouldBeRefreshed interface that you can implement to indicate that the class instance should be refreshed on every request.

Conclusion

Blink is a newcomer and still in its early development stages. You can collaborate by writing documentation for different components and send pull requests for new features. If you have any questions or comments you can post them below and let us know what you think about this new framework!

What makes the Blink Framework faster than traditional PHP?

The Blink Framework is designed to be a high-performance PHP framework. It achieves this by using Swoole, a coroutine-based PHP extension, which allows PHP to handle concurrent requests within a single thread. This is a significant departure from the traditional PHP model, which creates a new process or thread for each request. By handling multiple requests concurrently within a single thread, the Blink Framework can significantly reduce the overhead and increase the speed of PHP applications.

How does the Blink Framework compare to other PHP frameworks?

The Blink Framework is designed with performance in mind, making it a strong choice for high-traffic applications. It uses Swoole, a PHP extension that allows for asynchronous, parallel, and high-performance network programming. This makes it faster and more efficient than traditional PHP frameworks that rely on the synchronous, single-threaded nature of PHP. However, it’s worth noting that the Blink Framework may require a higher level of technical expertise to implement and manage compared to more user-friendly PHP frameworks.

Can I use the Blink Framework with my existing PHP application?

Yes, you can use the Blink Framework with your existing PHP application. However, it’s important to note that the Blink Framework uses a different model of handling requests compared to traditional PHP. This means that you may need to make some modifications to your application to take full advantage of the performance benefits offered by the Blink Framework.

How do I install the Blink Framework?

The Blink Framework can be installed using Composer, a dependency management tool for PHP. You can install Composer and then use it to install the Blink Framework by running the appropriate commands in your terminal or command prompt. Detailed installation instructions can be found in the Blink Framework’s official documentation.

What is Swoole and how does it work with the Blink Framework?

Swoole is a coroutine-based PHP extension that allows PHP to handle concurrent requests within a single thread. It’s a key component of the Blink Framework, enabling it to achieve high performance by reducing the overhead associated with creating a new process or thread for each request. Swoole also provides a range of other features, including HTTP and WebSocket servers, task scheduling, and more.

What are the system requirements for running the Blink Framework?

The Blink Framework requires PHP 7.1 or later and the Swoole extension. It’s also recommended to have Composer installed for managing dependencies. The Blink Framework can run on any operating system that supports PHP and Swoole, including Linux, macOS, and Windows.

How does the Blink Framework handle database connections?

The Blink Framework provides a simple and intuitive API for working with databases. It supports both SQL and NoSQL databases, and uses the PDO extension for SQL databases. The Blink Framework also supports database connection pooling, which can significantly improve performance for applications that make heavy use of the database.

Can I use the Blink Framework for developing APIs?

Yes, the Blink Framework is well-suited for developing APIs. It provides a range of features that make it easy to build and manage APIs, including routing, request handling, and response formatting. The Blink Framework also supports JSON and XML response formats out of the box, making it easy to build APIs that can be consumed by a wide range of clients.

How does the Blink Framework handle sessions and cookies?

The Blink Framework provides built-in support for sessions and cookies, making it easy to manage user sessions and persist data across requests. The Blink Framework’s session and cookie handling is designed to be secure and efficient, with support for encrypted cookies and session storage in a variety of backends, including files, databases, and caches.

What kind of support is available for the Blink Framework?

The Blink Framework is an open-source project, and support is primarily provided through the project’s GitHub repository. Users can report issues, submit pull requests, and contribute to the project’s development. There’s also a community of users and developers who can provide help and advice through various online forums and discussion groups.

Younes RafieYounes Rafie
View Author

Younes is a freelance web developer, technical writer and a blogger from Morocco. He's worked with JAVA, J2EE, JavaScript, etc., but his language of choice is PHP. You can learn more about him on his website.

BlinkBrunoSOOPHPoptimizationperformance-toolsPHPphp frameworkphp frameworks
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week