Skip to content
beginner Phase 5 · PHP OOP

PSR-4 Namespaces and Autoloading in PHP

Master PSR-4 namespaces, use statements, namespace resolution, and Magento's Vendor\Module namespace convention.

1h
0 problems
Topic Progress 0%

Namespace Declaration and Use Statements

Declaring Namespaces

<?php
// Every file should have one namespace declaration
// Must be the first statement (before any code)

namespace Vendor\Module\Model;

class Product
{
    // This class is now Vendor\Module\Model\Product
}

Namespace Hierarchy

Vendor/
  Module/
    Controller/
      Index/
        Index.php        -> Vendor\Module\Controller\Index\Index
    Model/
      Product.php        -> Vendor\Module\Model\Product
      ProductRepository.php -> Vendor\Module\Model\ProductRepository
    Block/
      Product/
        View.php         -> Vendor\Module\Block\Product\View
    Api/
      Data/
        ProductInterface.php -> Vendor\Module\Api\Data\ProductInterface
    etc/
      di.xml
      module.xml

Use Statements

<?php
namespace Vendor\Module\Service;

// Import classes with use statement
use Magento\Catalog\Model\Product;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\Exception\NoSuchEntityException;
use Psr\Log\LoggerInterface;

class ProductPriceService
{
    public function __construct(
        private ProductRepositoryInterface $productRepo,
        private LoggerInterface $logger
    ) {}

    public function getPrice(int $productId): float
    {
        try {
            $product = $this->productRepo->getById($productId);
            return $product->getPrice();
        } catch (NoSuchEntityException $e) {
            $this->logger->error('Product not found: ' . $productId);
            return 0.0;
        }
    }
}

// Alias long namespace names
use Magento\Framework\View\Element\Template as TemplateBlock;
use Vendor\Module\Helper\Data as ModuleHelper;

// Import functions (PHP 5.6+)
use function strlen;
use function array_map;

// Import constants (PHP 5.6+)
use const PHP_INT_MAX;

Using Classes Without Import

<?php
namespace Vendor\Module\Service;

// WITHOUT use statement - must use full namespace
$dateTime = new \DateTimeImmutable();
$arrayObject = new \ArrayObject();

// WITH use statement - cleaner
class OrderService
{
    private \Magento\Sales\Model\OrderFactory $orderFactory;

    public function __construct(
        \Magento\Sales\Model\OrderFactory $orderFactory
    ) {
        $this->orderFactory = $orderFactory;
    }
}

// With use statement
class OrderService
{
    public function __construct(
        private \Magento\Sales\Model\OrderFactory $orderFactory
    ) {}
}

Key Takeaway

Namespaces organize code into logical groups. Use use statements to import classes. Every file should declare its namespace as the first statement. Follow the Vendor\Module\Layer\Class convention.

Namespace Resolution

Resolution Types

<?php
namespace Vendor\Module\Service;

// Absolute namespace (starts with \)
$now = new \DateTimeImmutable();  // Global namespace
$pdo = new \PDO('mysql:host=localhost');

// Relative namespace (no leading \)
// Looks in current namespace first, then global
$model = new \Magento\Framework\Model\AbstractModel();

// self:: refers to current class
self::someMethod(); // Calls method in this class

// parent:: refers to parent class
parent::someMethod(); // Calls parent's method

// static:: refers to the class the method is called on (late static binding)
class Base
{
    public static function create(): static
    {
        return new static(); // Returns the calling class, not Base
    }
}

class Child extends Base {}

$child = Child::create(); // Returns Child instance, not Base

Namespace Resolution Examples

<?php
namespace Vendor\Module\Helper;

use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\ScopeInterface;

class Data extends AbstractHelper
{
    // Absolute: \DateTimeImmutable (global namespace)
    // Relative: ScopeInterface (looks in current namespace first)
    // Imported: AbstractHelper (via use statement)

    public function formatDate(\DateTimeImmutable $date): string
    {
        return $date->format('Y-m-d');
    }

    public function getStoreConfig(string $path, int $storeId = null): ?string
    {
        return $this->scopeConfig->getValue(
            $path,
            ScopeInterface::SCOPE_STORE,
            $storeId
        );
    }
}

Class vs Function vs Constant Resolution

<?php
namespace Vendor\Module\Service;

// Classes resolve with use statements
use Magento\Catalog\Model\Product;

// Functions use 'use function'
use function strlen;
use function array_map;

// Constants use 'use const'
use const PHP_INT_MAX;
use const Vendor\Module\Constants::MAX_PRODUCTS;

class ProductService
{
    public function process(string $data): void
    {
        $length = strlen($data);  // Uses imported function
        $max = PHP_INT_MAX;       // Uses imported constant

        // Class from use statement
        $product = new Product();
    }
}

Namespaces in Magento Modules

app/code/Vendor/Module/
├── Block/
│   └── Product/
│       └── View.php          # Vendor\Module\Block\Product\View
├── Controller/
│   ├── Index/
│   │   └── Index.php         # Vendor\Module\Controller\Index\Index
│   └── Product/
│       └── View.php          # Vendor\Module\Controller\Product\View
├── Helper/
│   └── Data.php              # Vendor\Module\Helper\Data
├── Model/
│   ├── Product.php           # Vendor\Module\Model\Product
│   ├── ResourceModel/
│   │   ├── Product.php       # Vendor\Module\Model\ResourceModel\Product
│   │   └── Product/
│   │       └── Collection.php # Vendor\Module\Model\ResourceModel\Product\Collection
│   └── ProductRepository.php  # Vendor\Module\Model\ProductRepository
├── Api/
│   └── Data/
│       └── ProductInterface.php # Vendor\Module\Api\Data\ProductInterface
├── Observer/
│   └── ProductSave.php        # Vendor\Module\Observer\ProductSave
├── Plugin/
│   └── ProductPlugin.php      # Vendor\Module\Plugin\ProductPlugin
├── etc/
│   ├── module.xml
│   ├── di.xml
│   └── events.xml
└── registration.php

Key Takeaway

Always use fully qualified names with a leading \ for global classes. Import classes with use statements for cleaner code. self:: refers to current class, static:: uses late static binding.

Magento Module Namespace Structure

Creating a Magento Module

<?php
// registration.php - registers the module
use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(
    ComponentRegistrar::MODULE,
    'Vendor_Module',
    __DIR__
);

Namespace Convention

<?php
// Module namespace: Vendor_Module
// PHP namespace: Vendor\Module

// Layer -> Sub-namespace
namespace Vendor\Module\Model;        // Model layer
namespace Vendor\Module\Block;        // Block layer
namespace Vendor\Module\Controller;   // Controller layer
namespace Vendor\Module\Helper;       // Helper layer
namespace Vendor\Module\Observer;     // Observer layer
namespace Vendor\Module\Plugin;       // Plugin layer
namespace Vendor\Module\Service;      // Service layer
namespace Vendor\Module\Api;          // API layer

// Sub-layer convention
namespace Vendor\Module\Model\ResourceModel;              // Resource models
namespace Vendor\Module\Model\ResourceModel\Product;     // Specific resource model
namespace Vendor\Module\Model\ResourceModel\Product\Collection; // Collections
namespace Vendor\Module\Api\Data;                          // Data interfaces

Complete Module Example

<?php
// Model\Product.php
namespace Vendor\Module\Model;

use Magento\Framework\Model\AbstractModel;
use Vendor\Module\Model\ResourceModel\Product as ProductResource;
use Vendor\Module\Api\Data\ProductInterface;

class Product extends AbstractModel implements ProductInterface
{
    protected function _construct()
    {
        $this->_init(ProductResource::class);
    }

    public function getName(): string
    {
        return $this->getData('name');
    }

    public function setName(string $name): self
    {
        return $this->setData('name', $name);
    }
}
<?php
// Model\ResourceModel\Product.php
namespace Vendor\Module\Model\ResourceModel;

use Magento\Framework\Model\ResourceModel\Db\AbstractDb;

class Product extends AbstractDb
{
    protected function _construct()
    {
        $this->_init('vendor_module_product', 'entity_id');
    }
}
<?php
// Model\ResourceModel\Product\Collection.php
namespace Vendor\Module\Model\ResourceModel\Product;

use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
use Vendor\Module\Model\Product;
use Vendor\Module\Model\ResourceModel\Product as ProductResource;

class Collection extends AbstractCollection
{
    protected function _construct()
    {
        $this->_init(Product::class, ProductResource::class);
    }
}
<?php
// Block\Product\View.php
namespace Vendor\Module\Block\Product;

use Magento\Framework\View\Element\Template;
use Magento\Framework\View\Element\Template\Context;
use Vendor\Module\Model\ProductFactory;

class View extends Template
{
    public function __construct(
        Context $context,
        private ProductFactory $productFactory,
        array $data = []
    ) {
        parent::__construct($context, $data);
    }

    public function getProduct(int $id): Product
    {
        return $this->productFactory->create()->load($id);
    }
}

Namespace Best Practices

1. One class per file
2. Namespace must be first statement in file
3. Use statement should follow namespace declaration
4. Match directory structure to namespace structure
5. Vendor name should be unique (e.g., YourCompany, not generic names)
6. Module name should be PascalCase: Vendor_ModuleName

Key Takeaway

Magento follows strict namespace conventions: Vendor\Module\Layer\SubLayer. The directory structure mirrors the namespace structure. One class per file, namespace declared first, use statements imported.

Quiz

1. What must be the first statement in a PHP file that uses namespaces?

Question 1 options

2. What does the \ (leading backslash) mean in namespace resolution?

Question 2 options

3. What does the 'use' keyword do in PHP?

Question 3 options

4. What is the Magento namespace convention for a module?

Question 4 options

5. What does 'as' do in a use statement?

Question 5 options

Flashcards

Question

What is a PHP namespace?

Answer

A way to organize code into logical groups and prevent class name conflicts. Declared with namespace Vendor\Module\Model; as the first statement in a file.

Question

What does the use statement do?

Answer

Imports a class, function, or constant so you can use its short name. Example: use Magento\Catalog\Model\Product; lets you write Product instead of the full path.

Question

What does a leading \ mean in namespace resolution?

Answer

Absolute namespace from the global root. \DateTimeImmutable refers to the global class, not one in the current namespace.

Question

What is Magento's module namespace convention?

Answer

Vendor\Module\Layer\Class. Example: Vendor\Module\Model\Product, Vendor\Module\Block\Product\View.

Question

What does 'use as' do?

Answer

Creates an alias for an imported class. use Long\Name\Class as Short; lets you use Short instead of the full name.

Question

What does 'use function' do?

Answer

Imports a function. use function strlen; lets you call strlen() without the global namespace prefix.

Question

What does self:: refer to?

Answer

The current class. Used to call methods or access properties of the class where the code is written, not the calling class.

Question

What does static:: refer to?

Answer

The class the method is called on (late static binding). Used in inheritance to refer to the child class, not the parent.

Revision Notes

Interview Tips

  • Explain the difference between absolute and relative namespace resolution
  • Know Magento's namespace convention (Vendor\Module\Layer\Class)
  • Describe when to use use statement vs full namespace path
  • Understand self:: vs static:: in inheritance
  • Be able to create a properly namespaced Magento module

Cheat Sheet

PHP Namespaces Cheat Sheet

Declaration:

namespace Vendor\Module\Model;

Import:

use Magento\Catalog\Model\Product;
use Long\Name\Class as Short;
use function strlen;
use const PHP_INT_MAX;

Resolution:
\ClassName - Absolute (global namespace)
ClassName - Relative (current then global)
self::method() - Current class
parent::method() - Parent class
static::method() - Called class (late binding)

Magento Convention:
Vendor\Module\Layer\Class
app/code/Vendor/Module/Layer/Class.php