Book Image

Phalcon Cookbook

By : Serghei Iakovlev, David Schissler
1 (2)
Book Image

Phalcon Cookbook

1 (2)
By: Serghei Iakovlev, David Schissler

Overview of this book

Phalcon is a high-performance PHP framework delivered as a PHP extension. This provides new opportunities for speed and application design, which until recently have been unrealized in the PHP ecosystem. Packed with simple learning exercises, technology prototypes, and real-world usable code, this book will guide you from the beginner and setup stage all the way to advanced usage. You will learn how to avoid niche pitfalls, how to use the command-line developer tools, how to integrate with new web standards, as well as how to set up and customize the MVC application structure. You will see how Phalcon can be used to quickly set up a single file web application as well as a complex multi-module application suitable for long-term projects. Some of the recipes focus on abstract concepts that are vital to get a deep comprehension of Phalcon and others are designed as a vehicle to deliver real-world usable classes and code snippets to solve advanced problems. You’ll start out with basic setup and application structure and then move onto the Phalcon MVC and routing implementation, the power of the ORM and Phalcon Query Language, and Phalcon’s own Volt templating system. Finally, you will move on to caching, security, and optimization.
Table of Contents (17 chapters)
Phalcon Cookbook
Credits
About the Authors
About the Reviewer
www.PacktPub.com
Preface
Index

Easily loading code on demand


Here you will learn how to load code on demand by using the PSR-4 compatible autoloading strategy. We notify the autoloader where the classes are located to load them on demand.

Getting ready

If you are familiar with PHP, you've surely heard of PSR-0 and PSR-4 standards, which make it possible to load the required classes automatically at the moment of their call without using such instructions as require and include.

The behavior of Phalcon\Loader is based on the PHP's capability of autoloading classes; if any class used in code doesn't exist, a special handler will try to find and load it. Phalcon\Loader is designed just for that operation. The loading of only the files needed for a particular class to operate has a positive impact on the application's performance. It helps to avoid wasteful computation, and reduces program memory requirements. This technology is called Lazy Initialization.

As of October 21, 2014, PSR-0 has been marked as deprecated. PSR-4 is now recommended as an alternative. Starting from version 3.0.0, the support for prefixes strategy in Phalcon\Loader is removed from Phalcon. For that very reason, loading with the use of the PSR-0 standard will be omitted here.

How to do it…

Follow these steps to complete this recipe:

  1. Create an autoloader instance in the following way:

    define('APP_PATH', realpath(dirname(dirname(__DIR__))));
    
    $loader = new \Phalcon\Loader();
    $loader->registerNamespaces([
      'MyBlog\Models'      => APP_PATH . '/app/models/',
      'MyBlog\Controllers' => APP_PATH . '/app/controllers/',
      'MyBlog\Library'     => APP_PATH . '/engine/',
    ]);
    
    $loader->register();
  2. Now, after configuring the loader in the way shown in the earlier code instance, create the class MyBlog\Models\Users, located in app/models/Users.php:

    <?php
    
    namespace MyBlog\Models;
    
    use Phalcon\Mvc\Model;
    
    class User extends Model
    {
    
    }
  3. Edit MyBlog\Controllers\IndexController in app/controllers/IndexController.php:

    <?php
    
    namespace MyBlog\Controllers;
    
    use Phalcon\Mvc\Controller;
    
    class IndexController extends Controller
    {
    
    }
  4. Edit MyBlog\Library\SomeClass in the engine/SomeClass.php:

    <?php
    
    namespace MyBlog\Library;
    
    class SomeClass
    {
    
    }

How it works…

The Phalcon\Loader::registerNamespaces method gets an associative array, identifying which keys are namespace prefixes and their values are directories where the classes are located in. For instance, after configuring the loader as shown earlier, we can use the following class, MyBlog\Models\Users, located in app/models/Users.php, MyBlog\Controllers\IndexController in app/controllers/IndexController.php, and MyBlog\Library\SomeClass in engine/SomeClass.php.

Let's consider in depth how the class search is carried out when using the namespaces strategy. Let's assume that you have registered the MyBlog\Library namespace for the engine directory, and then called the class MyBlog\Library\Some\Example. After registration, the autoloader knows that the MyBlog\Library namespace belongs to the engine directory. Next, in the remaining part of the class name (\Some\Example), the namespace separator (\) will be replaced with the directory separator (/), and the file extension will be added. Eventually, this will result in forming the path engine/Some/Example.php. So, in such a simple and quite fast way, the class loading with the use of the namespace strategy is performed.

It is defined in the PSR-4 standard that the vendor/package pair can refer to any directory or even more. That's why you can easily register the same namespace to be served by several directories:

define('ROOT_PATH', realpath(dirname(dirname(__DIR__))));

$loader = new \Phalcon\Loader();

$loader->registerNamespaces([
  'Phalcon' => ROOT_PATH . '/app/library/Phalcon/',
]);

$loader->register();

We have used the Phalcon namespace here, regardless of the fact that it is already registered by the framework. There is no conflict here. Using the Phalcon namespace, PHP will try to find the class among the classes provided by the framework, and after failing to find it, it will try to find it in the directory app/library/Phalcon/.

Note that when registering a namespace, which already exists, and an identical class name in this namespace, you will not be able to call this class. For example, if you register the namespace as previously described, and create the Phalcon\Crypt class, located in app/library/Phalcon/Crypt.php, you will not be able to call it in the following way: $cryp = new Phalcon\Crypt(). This is due to the fact that the Phalcon PHP extension is initialized at the earlier stage and PHP knows already about the Phalcon\Crypt class.

But let's return to our Phalcon namespace, which we have registered before. Now, if we try to create a new class:

$myHelper = new Phalcon\MyHelper();

Phalcon will search for it in the file app/library/Phalcon/MyHelper.php. Just due to the fact that Phalcon\Loader uses the fully PSR-4 compatible autoloader, we have no problems with class autoloading when applying such libraries as Phalcon Incubator and Phalcon Developer Tools, using the Phalcon namespace.

Furthermore, Phalcon\Loader provides other class-loading strategies, which are not PSR-4 compatible. We'll consider them briefly later.

Phalcon\Loader, as with most autoloaders, provides class loading with the use of directories. This class loading strategy isn't PSR-4 compatible, but it is efficient, and in certain situations, adequate. The loading with the use of directories comes down to the enumeration of all possible directories in an attempt to search for your classes. The Phalcon\Loader::registerDirs method receives the array of directories, in which the search will perform:

define('ROOT_PATH', realpath(dirname(dirname(__DIR__))));

$loader = new \Phalcon\Loader();
$loader->registerDirs([
  ROOT_PATH . '/components/',
  ROOT_PATH . '/adapters/',
  ROOT_PATH . '/engine/',
]);

$loader->register();

We have told the autoloader that our classes are located in three directories: components, adapters, and engine. Note that this strategy is the slowest. Class registering with the use of directories means that, by calling any class, Phalcon will search through these directories to find a class with the same name as the required class. As our project grows, this type of search will have an impact on performance. When using this class loading strategy, it is important to be mindful of the order of your directories, because you could create two classes with the same name in two different directories. If there is one class named Example in each of the following directories, components and engine, then, by calling the class:

$myComponent = new Example();

The first found class will be used which is the one from the components directory.

The third option, which can help you register your classes with the use of the Phalcon\Loader component, is registering classes. This autoloading method is not PSR-4 compatible, but in some cases it is the fastest. This solution may be efficient when using strategies which don't allow for easy retrieval of the file using the namespace and the class directory. The following describes how we can register classes in this way:

define('ROOT_PATH', realpath(dirname(dirname(__DIR__))));
$loader = new \Phalcon\Loader();
$loader->registerClasses([
  ROOT_PATH . '/components/Awesome/Example.php',
  ROOT_PATH . '/adapters/Base/BaseAdaper.php'
]);
$loader->register();

The Phalcon\Loader:registerClasses method gets the array of files, among which the search will be performed. Here we have told the autoloader about two classes, Example and BaseAdapter, and specified the full path to them. For example, now when calling the class $example = new Example(), the class located in components/Awesome/Example.php will be used. Although this method is the fastest, your file list will grow significantly, and with it the time it takes for the search to be carried out, so it will reduce the performance.

The Phalcon\Loader component allows you to combine autoloading options. There is no reason why you shouldn't use them all together, if you needed:

define('ROOT_PATH', realpath(dirname(dirname(__DIR__))));
$loader = new \Phalcon\Loader();
$loader->registerNamespaces([
  'MyBlog\Models'      => ROOT_PATH . '/app/models/',
  'MyBlog\Controllers' => ROOT_PATH . '/app/controllers/',
  'MyBlog\Library'     => ROOT_PATH . '/engine/',
]);
$loader->registerDirs([
  ROOT_PATH . '/components/',
  ROOT_PATH . '/adapters/',
  ROOT_PATH . '/engine/',
]);
$loader->registerClasses([
  ROOT_PATH . '/vendor/awesome/plugins/Example.php',
  ROOT_PATH . '/adapters/Base/BaseAdaper.php'
]);
$loader->register();

In such a manner, we can register the namespaces, the directories, and the classes.

In summary, it should be mentioned that the strategies that are based on the namespaces are faster than those based on the directories. In some cases, the strategy based on the class registering is faster, but only if your project has a small number of classes. In a relatively large project, the fastest strategy is to register the namespaces.

Note

The loader is case-sensitive.

Finally, if the APC is enabled, it will be used for the requested file (and this file will be cached).

There's more…

For more information about Lazy Initialization, go to:

https://en.wikipedia.org/wiki/Lazy_initialization.

For more detailed information about the PSR-0 standard refer to:

http://www.php-fig.org/psr/psr-0/, about the PSR-4 standard refer to http://www.php-fig.org/psr/psr-4/.