📜 ⬆️ ⬇️

PHP Namespace

I recently encapsulated my project in a namespace and ran into the problem of the lack of normal documentation. Everything that could be found dates back to about 2009, and almost 2012 is in the courtyard ... There are a lot of non-working places in the material found that use the current version of php. In this regard, I want to highlight this issue.
So what is Namespace or namespace? Great wikipedia defines them like this:
A namespace is a set that means a model, an abstract repository, or an environment created for the logical grouping of unique identifiers (that is, names). An identifier defined in a namespace is associated with this space. The same identifier can be independently defined in several spaces. Thus, the value associated with an identifier defined in one namespace may (or may not) have the same (or rather, different) meaning, like the same identifier defined in another space. Languages ​​with namespace support define rules that indicate to which namespace the identifier belongs (that is, its definition). wiki


All clear? In fact, everything is simple. Before version 5.3, php had only two spaces - global (in which your main code was executed) and local (in which function variables were defined).
image
Since version 5.3 everything has changed. Now you can define your own namespace, in which your classes will exist, methods, etc.
image
I hope it became a little clearer.

I specifically called classes the same way. Since they are defined in different spaces, they are two different classes, despite the same names. The main script, as before, functions in the global space, nothing has changed here, and in it, as before, classes and functions can be defined. So what is the use of space then? First of all, to ensure that when you connect a file, with some framework or library, your classes will not override the framework classes or vice versa.
')
In order to use the classes defined in your namespace, you need in the right place (I usually prefer to do it at the beginning of the file) to import the space you defined into the global one.
use 

Warning: for some reason, php does not allow the use of the use keyword in blocks of conditions and cycles.


Let's take an example from the pictures and put it in the code:
Attention: the namespase keyword must be located at the very beginning of the file immediately after <? php

A.php file
 <? php namespace A { class A { public static function say() { echo '   '; } } } 

B.php file
 <? php namespace B { class A { public static function say() { echo '   B'; } } } 

Alternative syntax is possible:
 <? php namespace A; class A { public static function say() { echo '   '; } } 


It is recommended to declare each namespace in a separate file. Although it is possible and in one, but it is strictly not recommended!
Now let's move to the third file in which our main script will function.
index.php
 <? php require_once 'A.php'; require_once 'B.php'; use A\A; use B\A; 

it would seem to be an advantage, only the code was added, but this is not quite so, a little further I will give an example of the autoload class, with which the lines connecting files with classes will be unnecessary.
Now turn to our classes.
 <? php require_once 'A.php'; require_once 'B.php'; use A\A; use B\A; A\A::say(); B\A::say(); 

Attention: the use of the scope resolution operator (: :) in php namespaces is not allowed ! The only thing for which it is suitable is to refer to static class methods and constants. At first they wanted to use it for the namespace, but then they refused because of the problems that arose. Therefore, the construction of the form A :: A :: say (); is invalid and will result in an error.

For namespaces, you must use the backslash character "\"
Attention: in order to avoid misunderstanding, it is necessary to escape this symbol when using it in the lines: '\\'


Namespaces can be nested into each other, add our A.php file:
 <? php namespace A { class A { public static function say() { echo '   '; } } } namespace A\subA { class A { public static function say() { echo '   '; } } } 

and in the index we write the following:
 <? php require_once 'A.php'; require_once 'B.php'; use A\A as A; use B\A as B; use A\subA as sub A::say(); A::say(); sub::say(); 


An important point is the use of aliases for imported spaces. You could write A \ subA :: say (); agree, to write full paths to spaces each time is difficult in order to avoid this aliases were introduced. When compiling, the following will happen instead of the sub alias: A \ subA, so we get the call A \ subA :: say ();

And what then happens when calling functions defined in the global space? PHP first searches for a function inside the space where you are currently working, and if it does not find it, it refers to the global scope. In order to immediately indicate that you are using a global function, you must put a backslash in front of it.

In order to avoid problems with autoloading of classes from spaces, the file system should be organized similarly to the organization of spaces. For example, we have a root folder classes, where our classes will be stored, then our spaces can be organized as follows
classes \ A \ A.php
classes \ A \ sub \ A.php (subspace sub put in a separate file)
classes \ B \ B.php

In php there is a magic constant __NAMESPACE__ which contains the name of the current space.

And now about autoload.


The class below is not mine, I just made it a worker and improved it a little bit from here .
Attention: In order for your classes to load the class name must match the file name!


 <?php namespace yourNameSpace { class Autoloader { const debug = 1; public function __construct(){} public static function autoload($file) { $file = str_replace('\\', '/', $file); $path = $_SERVER['DOCUMENT_ROOT'] . '/classes'; $filepath = $_SERVER['DOCUMENT_ROOT'] . '/classes/' . $file . '.php'; if (file_exists($filepath)) { if(Autoloader::debug) Autoloader::StPutFile((' ' .$filepath)); require_once($filepath); } else { $flag = true; if(Autoloader::debug) Autoloader::StPutFile(('  ')); Autoloader::recursive_autoload($file, $path, &$flag); } } public static function recursive_autoload($file, $path, $flag) { if (FALSE !== ($handle = opendir($path)) && $flag) { while (FAlSE !== ($dir = readdir($handle)) && $flag) { if (strpos($dir, '.') === FALSE) { $path2 = $path .'/' . $dir; $filepath = $path2 . '/' . $file . '.php'; if(Autoloader::debug) Autoloader::StPutFile(('  <b>' .$file .'</b> in ' .$filepath)); if (file_exists($filepath)) { if(Autoloader::debug) Autoloader::StPutFile((' ' .$filepath )); $flag = FALSE; require_once($filepath); break; } Autoloader::recursive_autoload($file, $path2, &$flag); } } closedir($handle); } } private static function StPutFile($data) { $dir = $_SERVER['DOCUMENT_ROOT'] .'/Log/Log.html'; $file = fopen($dir, 'a'); flock($file, LOCK_EX); fwrite($file, ('â•‘' .$data .'=>' .date('dmY H:i:s') .'<br/>â•‘<br/>' .PHP_EOL)); flock($file, LOCK_UN); fclose ($file); } } \spl_autoload_register('yourNameSpace\Autoloader::autoload'); } 

If you look at the names of the classes that come to be loaded, then you will see that each class is preceded by a prefix from the namespace, which is specified in use. That is why I recommend using the location of files in directories similar to the namespace, it speeds up the search to one or two iterations.

Now our index can be written like this:
 <? php require_once 'Autoloader.php'; use Autoloader as Autoloader; use A\A as A; use B\A as B; use A\subA as sub A::say(); A::say(); sub::say(); 

now all the classes and interfaces that you will use will be loaded automatically.

To demonstrate some of the dynamic capabilities of a language with spaces, let's declare another class:
test.php
 <? php namespace mySpace { class test { __construct() { //; } function sayName($name) { echo ' ' . $name; } static function sayOther() { echo ' '; } } } 


index.php
 <? php require_once 'Autoloader.php'; use Autoloader as Autoloader; use mySpace\test as test //,    $class = 'test'; //    $obj = new $class; $obj->sayName('test'); //   test\sayName('test2'); //  $obj::sayName('test'); //   test::sayName('test2'); 


I hope that my article will be useful to someone.

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


All Articles