MidТеория4 min

Пространства имён

use, as, групповые импорты, autoloading, PSR-4

Пространства имён (Namespaces)

Зачем нужны пространства имён

Пространства имён решают две проблемы:

  1. Конфликт имён — два класса/функции с одинаковым именем из разных библиотек
  2. Организация кода — логическая группировка связанных классов
<?php
// Without namespaces — name collision!
// class Logger {}  // Your class
// class Logger {}  // Library class — FATAL ERROR!

// With namespaces — no problem
namespace App\Logging;
class Logger {}

namespace Vendor\Logging;
class Logger {}

Объявление пространства имён

<?php
declare(strict_types=1);

namespace App\Entity;

// Everything in this file belongs to App\Entity namespace
class User
{
    public function __construct(
        private readonly string $name,
        private readonly string $email,
    ) {
    }
}

class Product
{
    public function __construct(
        private readonly string $title,
        private readonly float $price,
    ) {
    }
}

Правила объявления

<?php
// namespace MUST be the first statement in the file
// (only declare() and comments can come before it)
declare(strict_types=1);

namespace App\Service;

// CORRECT: declare before namespace is allowed
<?php
// WRONG: code before namespace
echo 'Hello';
// namespace App\Service; // Fatal error!

Ловушка экзамена: namespace должен быть первым оператором в файле. Единственное, что может стоять перед ним — declare(strict_types=1); и комментарии. Любой другой код до namespace вызовет Fatal Error.

Вложенные пространства имён

<?php
declare(strict_types=1);

// Sub-namespaces use backslash separator
namespace App\Entity\User;

class Profile {}
// Full name: App\Entity\User\Profile

Использование классов из других пространств

Полное квалифицированное имя (FQCN)

<?php
declare(strict_types=1);

namespace App\Service;

class UserService
{
    public function createUser(): \App\Entity\User
    {
        // Backslash at the beginning = absolute path
        return new \App\Entity\User('Alice', '[email protected]');
    }

    public function log(): void
    {
        // Global namespace functions/classes need leading backslash
        $date = new \DateTime();
        \var_dump($date);
    }
}

Импорт с use

<?php
declare(strict_types=1);

namespace App\Service;

use App\Entity\User;
use App\Entity\Product;
use App\Repository\UserRepository;

class UserService
{
    public function __construct(
        private readonly UserRepository $repository,
    ) {
    }

    public function createUser(string $name, string $email): User
    {
        // Now we can use short names
        return new User($name, $email);
    }
}

Псевдонимы (as)

<?php
declare(strict_types=1);

namespace App\Service;

use App\Entity\User as AppUser;
use Vendor\Auth\User as AuthUser;
use App\Entity\Product;

class ImportService
{
    public function convert(AuthUser $authUser): AppUser
    {
        return new AppUser(
            $authUser->getName(),
            $authUser->getEmail(),
        );
    }
}

Групповой импорт (PHP 7.0+)

<?php
declare(strict_types=1);

namespace App\Controller;

// Group use declarations
use App\Entity\{User, Product, Order};
use App\Service\{UserService, ProductService};
use App\Repository\{
    UserRepository,
    ProductRepository,
    OrderRepository,
};

// Mixed group use (classes, functions, constants)
use App\Utils\{
    Helper,                     // Class
    function formatDate,         // Function
    function formatMoney,        // Function
    const MAX_RETRIES,          // Constant
    const DEFAULT_TIMEOUT,      // Constant
};

Импорт функций и констант

<?php
declare(strict_types=1);

namespace App\Service;

// Import a function
use function App\Utils\formatDate;
use function App\Utils\formatMoney;

// Import a constant
use const App\Config\MAX_RETRIES;
use const App\Config\DB_HOST;

class PaymentService
{
    public function process(): string
    {
        $date = formatDate(time());       // Imported function
        $retries = MAX_RETRIES;           // Imported constant
        return "Processed at {$date}, max retries: {$retries}";
    }
}

Глобальное пространство имён

<?php
declare(strict_types=1);

namespace App\Service;

class FileService
{
    public function readFile(string $path): string
    {
        // Global functions: PHP first checks current namespace,
        // then falls back to global
        $content = file_get_contents($path);  // Works! Falls back to global

        // But for classes — NO fallback!
        // $dt = new DateTime();  // Error: App\Service\DateTime not found!
        $dt = new \DateTime();    // Must use backslash for global classes

        // Exception class also needs backslash
        throw new \RuntimeException('Error');
        // NOT: throw new RuntimeException(); — would look in App\Service\
    }
}

Ловушка экзамена: Для функций и констант PHP делает fallback в глобальное пространство имён, если не находит в текущем. Для КЛАССОВ fallback НЕ РАБОТАЕТ — нужно явно указывать \ClassName или использовать use. Это одно из самых частых заблуждений!

Таблица резолюции имён

Тип Полное имя Относительное Fallback
Классы \App\Entity\User User (с use) НЕТ
Функции \strlen() strlen() ДА (глобальная)
Константы \PHP_INT_MAX PHP_INT_MAX ДА (глобальная)

Автозагрузка (Autoloading)

spl_autoload_register

<?php
declare(strict_types=1);

// Custom autoloader
spl_autoload_register(function (string $className): void {
    // Convert namespace to file path
    // App\Entity\User => src/Entity/User.php
    $path = str_replace('\\', DIRECTORY_SEPARATOR, $className);
    $file = __DIR__ . '/src/' . $path . '.php';

    if (file_exists($file)) {
        require $file;
    }
});

// Now classes are loaded automatically
$user = new App\Entity\User('Alice', '[email protected]');

PSR-4 стандарт автозагрузки

Namespace prefix    => Base directory
App\                => src/
App\Entity\User     => src/Entity/User.php
App\Service\Auth    => src/Service/Auth.php

Правила PSR-4:

  1. Каждый класс — в отдельном файле
  2. Имя файла совпадает с именем класса (с учётом регистра)
  3. Пространство имён соответствует структуре директорий
  4. Используется один базовый каталог для корневого пространства имён

Composer autoload

{
    "autoload": {
        "psr-4": {
            "App\\": "src/",
            "Tests\\": "tests/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    }
}
<?php
declare(strict_types=1);

// In your bootstrap/entry file
require __DIR__ . '/vendor/autoload.php';

// All PSR-4 compliant classes are now auto-loaded
use App\Service\UserService;
use App\Entity\User;

$service = new UserService();

Запомни: Composer реализует PSR-4 автозагрузку. После изменения секции autoload в composer.json нужно выполнить composer dump-autoload для обновления карты классов.

Множественные пространства имён в одном файле

<?php
declare(strict_types=1);

// Method 1: Bracketed syntax (only way for multiple namespaces)
namespace App\Entity {
    class User {}
}

namespace App\Service {
    use App\Entity\User;

    class UserService
    {
        public function getUser(): User
        {
            return new User();
        }
    }
}

// Global namespace code
namespace {
    // Code in global namespace
    $service = new App\Service\UserService();
}

Ловушка экзамена: Нельзя смешивать простой синтаксис namespace X; и скобочный namespace X { } в одном файле. Если используете несколько namespace в файле — только скобочный синтаксис. На практике — один namespace на файл (PSR-4).

Магические константы пространства имён

<?php
declare(strict_types=1);

namespace App\Entity;

class User
{
    public function info(): void
    {
        echo __NAMESPACE__;     // 'App\Entity'
        echo __CLASS__;         // 'App\Entity\User'
        echo __FUNCTION__;      // 'info'
        echo User::class;       // 'App\Entity\User'
        echo self::class;       // 'App\Entity\User'
        echo static::class;     // Resolved at runtime (late static binding)
    }
}
<?php
declare(strict_types=1);

namespace App\Service;

use App\Entity\User;

// ::class resolution
echo User::class;           // 'App\Entity\User' (fully qualified)
echo UserService::class;    // 'App\Service\UserService'

// Dynamic class name (PHP 8.0+)
$obj = new User('test', '[email protected]');
echo $obj::class;           // 'App\Entity\User' (works on instances!)

Запомни: ClassName::class всегда возвращает полное квалифицированное имя класса (FQCN) в виде строки. Это работает и с use — use App\Entity\User; echo User::class; вернёт 'App\Entity\User', а не просто 'User'. С PHP 8.0+ работает и на экземплярах: $obj::class.


Вопросы с экзамена ZCE

Проверь себя

5 из 13

Рассмотрите следующий XML-документ. Что в нём неправильно и как исправить? ```php <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>XML Example</title> </head> <body> <p> Moved to <<a href="http://example.org/">http://www.example.org/</a>.> <br> </p> </body> </html> ```

Выберите все правильные варианты

Какая функция создаёт XML-парсер с поддержкой пространств имён?

Функция `world()` определена в глобальном пространстве имён `hello`. Ваш код находится в namespace `myapp`. Как правильно импортировать namespace, чтобы использовать функцию `world()`?

Какой оператор является допустимым разделителем пространств имён в PHP?

Какой метод автоматически вызывается при попытке создать экземпляр несуществующего класса?