Paul
Paul

Reputation: 11

using php namespaces correctly

I have just started rebuilding my app i made to use namespaces to make future development easier and so we can reuse class names.

basically my code is as follows.

<?php
session_start();

error_reporting(E_ALL);
ini_set('display_errors', 1);

use core\marketing as marketing;
use core\security as security;
use core\structure as structure;
use core\data as data;

include 'marketing\cleanurl.php';
?>

As soon as I run this I get the following error:

Warning: include(marketing\cleanurl.php): failed to open stream: No such file or directory in /var/www/index.php on line 27 Warning: include(): Failed opening 'marketing\cleanurl.php' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/index.php on line 27

My directory structure matches the namespaces as that is what I read on the net.

Now if I change the include to match the directory i.e.

include 'core/marketing/cleanurl.php';

I get the following error

Parse error: syntax error, unexpected T_CLASS, expecting T_NS_SEPARATOR or ';' or '{' in /var/www/twiggled/core/marketing/cleanurl.php on line 4

This all worked when I was just using require_once to call all the classes but found this limited expansion of the system and made changes more time consuming and wanted to use namespaces as they have always been great in other languages I have used.

Upvotes: 1

Views: 6098

Answers (1)

eyecatchUp
eyecatchUp

Reputation: 10560

Since OP asked for it, here's an updated answer using autoload.

Note: Such a complex construct wouldn't be needed for the ease of task, of course. However, This is just an example how things play together (autoloading, requires, static methods etc).

Bootstrap / Autoload

/var/www/somedir/Twiggled/bootstrap.php

<?php
namespace Twiggled;

require_once __DIR__ . '\Common\AutoLoader.php';

$autoloader = new \Twiggled\Common\AutoLoader(__NAMESPACE__, dirname(__DIR__));
$autoloader->register();

/var/www/somedir/Twiggled/Common/AutoLoader.php

<?php
namespace Twiggled\Common;

/**
 * PSR-0 Autoloader
 *
 * @package    Common
 */
class AutoLoader
{
    /**
     * @var string The namespace prefix for this instance.
     */
    protected $namespace = '';

    /**
     * @var string The filesystem prefix to use for this instance
     */
    protected $path = '';

    /**
     * Build the instance of the autoloader
     *
     * @param string $namespace The prefixed namespace this instance will load
     * @param string $path The filesystem path to the root of the namespace
     */
    public function __construct($namespace, $path)
    {
        $this->namespace = ltrim($namespace, '\\');
        $this->path      = rtrim($path, '/\\') . DIRECTORY_SEPARATOR;
    }

    /**
     * Try to load a class
     *
     * @param string $class The class name to load
     *
     * @return boolean If the loading was successful
     */
    public function load($class)
    {
        $class = ltrim($class, '\\');

        if (strpos($class, $this->namespace) === 0) {
            $nsparts   = explode('\\', $class);
            $class     = array_pop($nsparts);
            $nsparts[] = '';
            $path      = $this->path . implode(DIRECTORY_SEPARATOR, $nsparts);
            $path     .= str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';

            if (file_exists($path)) {
                require $path;
                return true;
            }
        }
        return false;
    }

    /**
     * Register the autoloader to PHP
     *
     * @return boolean The status of the registration
     */
    public function register()
    {
        return spl_autoload_register(array($this, 'load'));
    }

    /**
     * Unregister the autoloader to PHP
     *
     * @return boolean The status of the unregistration
     */
    public function unregister()
    {
        return spl_autoload_unregister(array($this, 'load'));
    }
}

Package files

/var/www/somedir/Twiggled/Core/Helper/Strings.php

<?php
namespace Twiggled\Core\Helper;

class Strings
{
    // Note: Eventhough the method use a global PHP function name,
    // there is no problem with it - thanks to namespace.
    public static function str_replace($str) 
    {
        $str = preg_replace('/\s/', '_', strtolower($str));
        return preg_replace('/[^a-zA-Z_]/', '', $str);
    }
}

/var/www/somedir/Twiggled/Core/Marketing/Cleanurl.php

<?php
namespace Twiggled\Core\Marketing;

use \Twiggled\Core\Helper\Strings as HelperStrings;

class Cleanurl 
{
    const BASE_URL = 'http://example.com/';
    public $cleanPath;

    public function __construct($str) 
    {
        $this->cleanPath= HelperStrings::str_replace($str);
    }
}

Load and use it..

/var/www/somedir/index.php

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('date.timezone', 'Europe/Berlin');

// Bootstrap the package / register autoloader
require_once __DIR__ . '\Twiggled\bootstrap.php';

use \Twiggled\Core\Marketing as Marketing;

try {
    $obj = new Marketing\Cleanurl('$This w-ork5s!');

    // prints 'http://example.com/this_works'.
    echo Marketing\Cleanurl::BASE_URL . $obj->cleanPath; 
} 
catch (\Exception $e) { }

Upvotes: 2

Related Questions