This post is not a translation of the article, as is customary, but of the report + presentation, therefore the text of the post is quite voluntary.I think everyone knows and obviously that PHP is one of the most popular programming languages in which many web projects are written, starting with personal homepage pages and ending with mastodons like Facebook, Vimeo, WordPress and even YouPorn.
PHP appeared in 1995, with full support for the PLO was only implemented in PHP5, which was released in 2005. During this time, a large amount of code was written, both good and bad, and more precisely, it was strongly outdated and heavily followed.
')
Many projects, as well as the PHP ecosystem as a whole, by now have begun to present a semblance of a busy urban quarter.

New versions of PHP
The new decade brought us PHP5.3 and PHP5.4, which, in addition to increasing the performance, carry a lot of buns! Here are just some of them:
1.
Namespaces (php 5.3)
namespace JoliCode\Conferences; use General\Talk\Session; class SymfonyLive extends Session { public function runPresentation() { } }
- They save from coincidences in the naming of classes;
- Reduce uncertainty;
- Avoiding long class naming.
2.
Anonymous functions and closures (php 5.3), and even inside objects (php 5.4)
$container['session'] = function ($c) { return new Session($c['session_storage']); };
3.
Phar archives (php 5.3)
Allowed to distribute libraries in the form of one connected phar-file.
4.
“goto” - what for .. ?? (php 5.3)
5.
Traits (php 5.4)
6. Short syntax of array declaration! (php 5.4)
function fruits() { return ['apple', 'banana', 'orange']; } echo fruits()[0];
and
many other
things .
Frameworks
New versions of PHP have become a catalyst for the emergence of frameworks. Among them, symfony, Zend Framework, Yii, CodeIgniter, CakePHP are worth mentioning. Almost all of them have been significantly updated in the released second versions.
One of these frameworks, Symfony2, is built on a
set of independent components , as well as a number of third-party solutions that use the new features of the PHP language and help you reanimate projects with outdated code.
Project resuscitation strategy
Imagine that your project has existed for 5 years. During this time:
- A large amount of functionality has been implemented;
- The project works in production;
- It is constantly used by a large audience of users;
- A large amount of data has accumulated;
- An experienced team has been formed around the project.
Wherein:
- Slowly the introduction of new functionality;
- The problem with the support of the project and its infrastructure;
- It is difficult to improve the existing functionality.

Path 1: The Big Bang
The most natural desire in such a situation is
to throw out all the code and rewrite it again! Imagine that we went this way. Undoubtedly, we will get satisfaction from the possibility of working with one of the new modern framework, forgetting about the old code, and in some places bydlokod, like a bad dream.
But, frankly, the process is likely to be quite large-scale, difficult and lengthy and will take at least 1 person-year to rewrite all the functionality. At the same time, the development of the existing version of the project will stop, which will cause financial losses to your project’s business and outflow of users who are not given enough attention. There will also be high risks that it will not be possible to fully transfer all the functionality to the new platform. One of the reasons for these risks will be the need to develop tools for migrating existing data to a new structure of storage systems.
Path 2: Be consistent
Therefore it is not necessary to chop off the shoulder, the strategy of gradual updating of the project will be more reasonable. At the same time, the development and support of the project will not stop, and therefore your business will not stop either. This approach will not allow the use of the new framework entirely in the project, but you can use its individual parts. The components of symfony2 in this case are very well suited, since they have no dependencies, while they provide point and seamless functionality.
Go to action
Step 1. Translate the project into PHP 5.3 or PHP 5.4

First we update PHP to at least PHP 5.3. We do this carefully, we will perform the update first on the dev-server and check that no parts of the system have fallen off. Then you can check on the prod server. At the same time, it is advisable to do this not on the whole project, but in the A / B testing mode, so that only some users will get to the new environment.
Once you are convinced that everything is working fine, you can move on.
Step 2. Prepare the foundation for future refactoring of the system

We connect key components: ClassLoader, DependencyInjection and HTTPFoundation. They will help us with refactoring and will be the foundation for connecting new components.
These and all the following components can be easily connected using the
Composer package manager. It allows you to concisely describe the dependencies of the project on third-party libraries in json-format, automatically install and update them, and also generate an autoload-file to connect them to the project. On Habré there is a
good article on how to use it.
In our case, the configuration file for Composer will look like this:
{ "autoload": { "psr-0": {} }, "name": "xavierlacot/blog", "description": "My old blog on steroids", "require": { "php": ">=5.3.3", "symfony/class-loader": "2.1.*", "symfony/dependency-injection": "2.1.*", "symfony/http-foundation": "2.1.*" } }
Install the components:
$ php composer.phar install Installing dependencies from lock file - Updating symfony/class-loader (dev-master)
And we connect them to our project:
<?php
Now we can use them!
ClassLoader. Standards for class autoload
A year and a half ago, the PHP community made several agreements, one of which, the
PSR-0 agreement , describes the rules and code requirements for compatibility with modern class autoloaders (the history of autoloaders is well written
here and
here )
In short, the standard allows two types of class naming:
Via namespace (modern approach) class: Symfony\Component\HttpFoundation\Request path: vendor/src/Symfony/Component/HttpFoundation/Request.php
Through underscores (PEAR standard, outdated approach) class: Twig_Extension_Core path: vendor/twig/lib/Twig/Extension/Core.php
At the same time, when the class file is connected, the autoloader automatically replaces the slash (\) and underscore (_) characters with the directory separator (/), adding the .php extension to the end.
The
ClassLoader component allows
you to organize autoloading of classes in accordance with the PSR-0 convention.
Step 3. Class refactoring and using ClassLoader
For example, we have a class for working with LDAP:
<?php class prefixedLdapConnector { public function __construct() {
We bring it to the PSR-0 standard:
<?php namespace Prefix\Ldap\Client; class Client { public function __construct() {
Register the Prefix top-level space in the ClassLoader:
use Symfony\Component\ClassLoader\UniversalClassLoader; $loader = new UniversalClassLoader(); $loader->registerNamespace('Prefix', __DIR__ . '/src/'); $loader->register();
Now when using the Prefix \ Ldap \ Client class in your code, ClassLoader will take care of its automatic loading:
Step 4. Refactoring request processing / response preparation. Using HttpFoundation

The
HTTPFoundation component simplifies the processing of incoming requests and the preparation of a server response.
Adding 2 lines to the project:
we get the $ request object, which knows everything about the incoming request:
- $ request-> request replaces $ _POST
- $ request-> query replaces $ _GET
- $ request-> cookies replace $ _COOKIE
- etc.
And similarly with Response:
use Symfony\Component\HttpFoundation\Response; $response = new Response(); $response->setContent('This will be the response content'); $response->headers->set('Content-Type', 'text/html'); $response->setStatusCode(200);
It would seem, why replace the usual PHP variables and methods with new classes. In fact, this approach has a number of advantages. First, it allows you to enter a more understandable level of abstraction for working with data request and response, presented in the form of objects. You can fully control the request and response from any area of your project. Secondly, this component has
been tested by many independent developers for compliance with security requirements. Third, the code that uses HTTPFoundation is much easier to test.
Step 5. We make the project functionality in services. Dependency Injection Component
In almost all projects, there are a number of functions for which different libraries, classes, or even program functions are responsible. The Dependency Injection component allows you to organize and centralize the process of creating and configuring objects that implement this or that functionality. Such objects may include the postal service, database manager, template engine and many others.

Suppose we have a class for sending emails:
<?php namespace Prefix\Mailer; class Mailer { $prefix = ''; public function send($to, $subject, $body) {
And in our code, mail is sent like this:
function saveUser($name, $email) { $mailer = new Mailer(); $mailer->send($user->getEmail(), 'Welcome ' . $user->getName(), 'A test'); }
Let's do a little refactoring, create a service container and register our mail class in it:
use Symfony\Component\DependencyInjection\ContainerBuilder; $container = new ContainerBuilder(); $container->register('mailer', 'Mailer');
Let's do the second small refactoring in the lines of sending a letter:
function saveUser($name, $email) {
These minor changes give several bonuses at once:
- The object of the Mailer class is created only once, even if we receive it from the service container elsewhere in the project;
- Mailer service can now be centrally configured;
- It is easy to replace it with another service.
Similarly, it is possible to design one library of a project after another in the form of services by organizing all the work through service calls.
Step 6. What's next?
Having connected the first three components of Symfony2, you can start using other equally
useful components using the same algorithm:
- Console - development of console scripts (called from the command line or by cron)
- Finder - search for files and folders
- Routing - allows you to set the correspondence between HTTP requests and a set of configurable parameters
- Templating - will provide everything you need to work with templates in the project
- other.
Step by step, component by component, your project will be gradually transformed and acquire a new life without any radical solutions. Good luck and enjoy refactoring!