minte9
LearnRemember / PHP



Without Namespaces (Old Way)

 
/** 
    Without namespaces (old way) - Class name collision
    PHP will throw a fatal error because both classes have the same name.
*/

// Logger class from VendorA
class Logger {
    public function log($message) {
        echo "VendorA Logger: " . $message;
    }
}

// Logger class from VendorB
class Logger {
    public function log($message) {
        echo "VendorB Logger: " . $message;
    }
}

/**
    > php old_way.php

    PHP Fatal error:  
    Cannot declare class Logger, because the name is already in use.
 */

Using Namespaces (Modern Way)

 
/**
    To avoid class name collision we use namespaces
 */

namespace VendorA;

 // Logger class from VendorA
class Logger {
    public function log($message) {
        echo "VendorA Logger: " . $message;
    }
}

namespace VendorB;

// Logger class from VendorB
class Logger {
    public function log($message) {
        echo "VendorB Logger: " . $message;
    }
}

$logger = new Logger();
$logger->log("Message from logger");

/**
    > php no_collision.php

    VendorB Logger: Message from logger
 */

Using the classes correctly

 
/**
    The correct way of using classes correctly in a script.
    We can use both Logger classes without issue.

    This is why modern PHP development, with Composer and PSR4-autoloading, 
    relies heavely on namespaces.
 */

namespace MyApp;

require 'vendor/vendorA/Logger.php';
require 'vendor/vendorB/Logger.php';

$loggerA = new \vendorA\Logger();
$loggerA->log("Logging with vendorA");

$loggerB = new \vendorB\Logger();
$loggerB->log("Logging with vendorB");

/**
    > php correct_way.php 

    VendorA Logger: Logging with vendorA
    VendorB Logger: Logging with vendorB
 */
./vendor/vendorA/Logger.php
 
namespace VendorA;

 // Logger class from VendorA
class Logger {
    public function log($message) {
        echo "VendorA Logger: " . $message . "\n";
    }
}
./vendor/vendorB/Logger.php
 
namespace VendorB;

// Logger class from VendorB
class Logger {
    public function log($message) {
        echo "VendorB Logger: " . $message . "\n";;
    }
}

Autoloading via PSR-4

 
/**
    Using autoloading via PSR-4.
    This is the standar way to load classes without requiring each file manually.

    Project structure:
    my_project/
        vendor/
            VendorA/
                Logger.php
            VendorB/
                Logger.php
    autoload_spl.php
    autoload_via_psr4.php
 */

require("autoload_custom.php");

use vendorA\Logger as LoggerA; // alias
use vendorB\Logger as LoggerB;

$loggerA = new LoggerA();
$loggerA->log("Logging with vendorA");

$loggerB = new LoggerB();
$loggerB->log("Logging with vendorB");

/**
    > php autoload_via_psr4.php

    VendorA Logger: Logging with vendorA
    VendorB Logger: Logging with vendorB
 */
./autoload.php
 
/**
    This autoloader automatically converts namespace paths into file paths 
    and include them dynamically.
 */

function classAutoLoader($class) {
    // Convert namespace to full file path
    $file = __DIR__ . '/vendor/' . str_replace("\\", "/", $class . ".php");

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

spl_autoload_register("classAutoLoader");

Autoloading via Composer

 
/**
    Instead of manually creating autoload.php, we can use Composer for PSR-4 autoloading.
    This method is more scalable and aligns with modern PHP development.

    Create composer.json:

    > composer init

    Then, modify composer.json to include:

        {
            ...
            "autoload": {
                "psr-4": {
                    "VendorA\\": "vendor/vendorA/",
                    "VendorB\\": "vendor/vendorB/"
                }
            }
        }

    Run composer autoload:

    > composer dump-autoload

    Project structure will be:

        my_project/
            vendor/
                composer/
                    autoload_psr4.php
                    autoload_real.php
                    ...
                VendorA/
                    Logger.php
                VendorB/
                    Logger.php
                autoload.php
        autoload_via_composer.php
 */

require "vendor/autoload.php"; // Now using Composer's autoload

use vendorA\Logger as LoggerA; // Uppercase paths
use vendorB\Logger as LoggerB;

$loggerA = new LoggerA();
$loggerA->log("Logging with vendorA");

$loggerB = new LoggerB();
$loggerB->log("Logging with vendorB");

/**
    > php autoload_via_composer.php

    VendorA Logger: Logging with vendorA
    VendorB Logger: Logging with vendorB
 */
./vendor/composer/autoload_psr4.php
 
// autoload_psr4.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'vendorB\\' => array($vendorDir . '/vendorB'),
    'vendorA\\' => array($vendorDir . '/vendorA'),
);

Namespaces Theory

A namespace is defined with the namespace keyword and a name. It must be declared before any other code. Once defined, the scope of the namespace applies to the entire file. For global namespace, use the namespace keyword without a name. This feature can only be used in conjunction with the curly bracket syntax.
 
namespace MyProject {
    // MyProject namespace ...
}

namespace {
    // Global namespace ...
}
A fully-qualified namespace is like an absolute path in a file system. A qualified name is like a relative path in a file system.
 
$a = new \myRoot\myLibrary\classes\myClass; // fully-qualified

$b = new myRoot\myLibrary\classes\myClass;
To reference classes in the global namespace, you must begin with backslash. The functions do not need backslash.
  
namespace myLibrary\classes;
$obj = new ArrayObject(); // Fatal error: Class not found

$obj = new \ArrayObject(); // Look here
echo strlen("Hello World"); // Corect, resolves to native function
In a large application it can become cumbersome to write out identifier names. You can import namespaces, classes and interfaces using the use keyword. This allows them to be referenced by an alias instead of their full name.
  
use com\yahoo as y;  // Look Here
use com\google as g;
Only unqualified and qualified names are affected by aliases. Fully-qualified names are not. Therefore, the following will not be affected by the defined aliases.
  
namespace myLibrary\classes {

    require_once('myLibrary/classes/myClass.php');
    use myLibrary\classes\myClass as Another;

    $a = new Another;
    $b = new \myLibrary\classes\myClass;

    // fully-qualified names are not affected by alias
}



  Last update: 23 days ago