📜 ⬆️ ⬇️

Functions Strike Back

In this topic I want to talk about the approach that has been exploited for several years.
Immediately I warn you, if you are a true fan of OOP, huge constructions and monstrous class diagrams, do not read.

In short, the essence of the concept is the transfer of a part of the unix way into PHP programming.
Specifically, the concept of simple programs that perform one function.

The background is as follows.

Working on many systems and doing a variety of OOP monsters using frameworks, I was constantly experiencing discomfort and a feeling of excessive verbosity.
Interface Hash, class Abstract_Hash, descendant of Hash_MD5 ...
In which there will be a single-line wrapper for the standard function.
Is it too much for simple hashing?

Usually, it is objected that this increases the readability, reusability and maintability of the code.
But imagine that we need to replace a specific implementation mechanism, according to the Strategy pattern?
We come to either abstract factories or search-n-replace in code.
It does not pull on KISS , and only exacerbates the problem.
And if the components are strongly connected?
I saw projects in which Zend Framework and Kohana were mixed, on the principle of “reuse of the Kodz”. And, by the way, it was also offered for money.
')
Entry delayed, get down to business.

I came to the aid of simple functions. Common functions with one purpose.
Such as:
function F_Standart_Random($Args)
{
return rand($Args['Min'],$Args['Max']);
}

or
function F_MonteCarlo_Random($Args)
{
return mt_rand($Args['Min'], $Args['Max']);
}

(Examples chose simpler in order not to weigh down the article)

Functions are named by convention of the form.
F__($Args)
(in one implementation there can be several functions, for example, for encryption, there are four of them: encryption, decryption, initialization, and installation of the vector).

Stored in a structure like:
/Drivers/Generate/Entropy/MonteCarlo.php
where “Generate / Entropy” is a kind of “namespace”.

The most interesting begins now.

They are called through the singleton class, let's call it Code. The Code class has one method, E [xecute]. In this case, I sacrificed readability in favor of brevity, since There are a lot of calls to this method.
Ideally, make a short alias, like _ ($ args), but gettext has already taken this name.

Method E is declared as
public static function E ($Namespace, $Function, $Args, $Driver = 'Default')


What does he do or can he do?

The list that goes on is a description of the capabilities of the real class, but in order to avoid accusations of PR, there will be no direct link.

Configuration is everything

From the configuration of your framework or application, it can take data on default implementations, eliminating the need to specify the last argument, and giving you the ability to manage the code from the config, for example, replacing the method of generating UIDs on the fly or replacing algorithms with a different ratio of accuracy / performance .

From my practice, I recall the deployment of an application written for PHP 5.2 on a server with PHP 5.1, in which there is no native JSON implementation.
Replacing the native with your bike took less than a minute.

You can also implement a smart sample that will replace specific implementations, depending on the time of day, the current load, the client's geography, here the restriction is just your imagination.
It would not be superfluous to mention fault tolerance, because a class can iterate over drivers (specific implementations), catch exceptions, and adjust its configuration.

Caish it

In this scheme, caching the results of executing any code is easily implemented.
To do this, just add to the configuration an indication of what namespace / function can be cached and for how long.
You can implement this with a separate E [xecute] C [ached] method in order not to make the logic of the main method heavier.

Remote function call

A simple RPC server, a block in the configuration that will indicate what exactly and where to perform, and you get the opportunity to transfer to the remote server some stern number-crushing operation without changing the code.

Deferred calls

To fasten the simplest queue server is a task that everyone can manage.
Call now, executed when it is convenient for us.
Great for functionality that returns nothing.

Feature level ACL

Only write-delete functions come to mind.
Your system may have its own area that needs microregulation.

You can also add profiling, logging and more.

Advantages of the approach, besides those already mentioned:


Minimalism

Functions are designed as simple as possible, in the spirit of unix, with the expectation of sharing.
For example, F_RSS2_Import accepts only strings and allows the developer to choose which mechanism to receive the RSS feed to choose.
Simple functions are easy to debug, they work quickly and are perfectly combined.
Unfortunately, many frameworks sin by mixing data acquisition and processing, which leads to the inversion of abstraction and verbosity.

Adding functionality through the file system.

The new implementation does not require changes in the program code - just configuring and copying the file to the right place. Peculiar Convention over naming | configuration.

Independence.

This is not always possible, but most functions can be made independent of the host system, without external calls and bindings.

This opens up opportunities for the exchange of code, solutions and developments. By the way, to integrate some code, you only need to wrap it in a function with a name by agreement.
At one time, I was able to transfer a collection of about 300 functions to a system developed by another person, porting my class to it.
For half an hour, I managed to do the same with the Zend Framework.

I note that the use of foreign classes is not so convenient - usually leads to bloatware, violation of conventions, etc.

Speed ​​and resources.

This is a topic for holivar, but it’s obvious that simple classes are more costly.

Cons, they are not enough.


Globality

Functions are included from external files, the global scope is clogged.
I did not notice the effect on performance, but the sediment remains.
At the moment, I am looking at anonymous functions that remain inside the Code Singleton.

A description of the format of the arguments.

More precisely, its absence.
An associative array is not the most annotated data structure. They save docblocks, but depriving the possibility of autocompletion in the IDE may scare away.
Although, in my experience, I did not notice any inconvenience.

Overhead is present.

Not as big as the classes, but, nevertheless, it is.

Readability code.

The issue is controversial, proper formatting and proper use minimizes the shock of multiple calls to the same method.
In real projects, there are not so many calls.

Object-oriented masturbation.

OOP for OOP has become so familiar that the approach I described is unlikely to gain popularity.

As part of the article, I have given simple examples, I will give a list of applications from real projects: conversion (Arabic-Roman, SI, XML, RSS, APML), input processing, output processing (emoticons, smart tags, dynamic tags in template engines), generation (random numbers , uids, passwords), routing in frameworks, slots, data acquisition (database abstraction), conditions, message transports, etc.

The purpose of the topic is only to tell about this method of organizing code, which helps me a lot.
This is not a crusade against the PLO, not the ultimate truth and not a guide to action (a reservation is needed here, after my first topic, in which I was accused that I personally misled billions of juniors).

If someone is interested in the implementation details, please in the comments.

Source: https://habr.com/ru/post/103465/


All Articles