Как использовать пространства имен PHP с автоматической загрузкой?


Я получаю эту ошибку при попытке использовать autoload и пространства имен:

фатальная ошибка: класс 'Class1' не найден в / usr / local/www/apache22/data/public/php5.3 / test.php on строка 10

может кто-нибудь сказать мне, что я делаю неправильно?

вот мой код:

Класс1.php:

<?php

namespace PersonBarnesDavid
{
    class Class1
    {
        public function __construct()
        {
            echo __CLASS__;
        }
    }
}

?>
13 85

13 ответов:

Class1 не находится в глобальной области видимости.

смотрите ниже для рабочего примера:

<?php

function __autoload($class)
{
    $parts = explode('\', $class);
    require end($parts) . '.php';
}

use Person\Barnes\David as MyPerson;

$class = new MyPerson\Class1();

Edit (2009-12-14):

просто чтобы уточнить, мое использование "use ... как" для упрощения примера.

альтернативой было следующее:

$class = new Person\Barnes\David\Class1();

или

use Person\Barnes\David\Class1;

// ...

$class = new Class1();

как уже упоминалось Паскаль Мартин, вы должны заменить ' \ ' с DIRECTORY_SEPARATOR например:

$filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('\', DIRECTORY_SEPARATOR, $class) . '.php';
include($filename);

также я бы предложил вам реорганизовать структуру dirrectory, чтобы сделать код более читаемым. Это может быть альтернативой:

каталог структуру:

ProjectRoot
 |- lib

File:/ProjectRoot/lib/Person/Barnes/David/Class1.php

<?php
namespace Person\Barnes\David
class Class1
{
    public function __construct()
    {
        echo __CLASS__;
    }
}
?>
  • создайте подкаталог для каждого определенного пространства имен.
: /ProjectRoot/test.php
define('BASE_PATH', realpath(dirname(__FILE__)));
function my_autoloader($class)
{
    $filename = BASE_PATH . '/lib/' . str_replace('\', '/', $class) . '.php';
    include($filename);
}
spl_autoload_register('my_autoloader');

use Person\Barnes\David as MyPerson;
$class = new MyPerson\Class1();
  • я использовал php 5 recomendation для объявления автозапуска. Если вы все еще используете PHP 4, замените его старым синтаксисом: function __autoload ($class)

код __autoload функция получит полное имя класса, включая имя пространства имен.

это означает, в вашем случае, получите 'Person\Barnes\David\Class1' и не только 'Class1'.

таким образом, вы должны изменить свой код автоматической загрузки, чтобы иметь дело с таким "более сложным" именем ; часто используемое решение заключается в организации ваших файлов с использованием одного уровня каталога на "уровень" пространств имен, а при автоматической загрузке замените '\ ' в имени пространства имен по DIRECTORY_SEPARATOR.

Я делаю что-то вроде этого: смотрите этот пример GitHub

spl_autoload_register('AutoLoader');

function AutoLoader($className)
{
    $file = str_replace('\',DIRECTORY_SEPARATOR,$className);

    require_once 'classes' . DIRECTORY_SEPARATOR . $file . '.php'; 
    //Make your own path, Might need to use Magics like ___DIR___
}

Я нашел этот перл от Flysystem

spl_autoload_register(function($class) {
    $prefix = 'League\Flysystem\';

    if ( ! substr($class, 0, 17) === $prefix) {
        return;
    }

    $class = substr($class, strlen($prefix));
    $location = __DIR__ . 'path/to/flysystem/src/' . str_replace('\', '/', $class) . '.php';

    if (is_file($location)) {
        require_once($location);
    }
});

Я вижу, что функции автоматической загрузки получают только" полное " имя класса - со всеми пространствами имен, предшествующими ему - в следующих двух случаях:

[a] $a = new The\Full\Namespace\CoolClass();

[b] use The\Full\Namespace as SomeNamespace; (at the top of your source file) followed by $a = new SomeNamespace\CoolClass();

Я вижу, что функции автоматической загрузки не получают полное имя класса в следующем случае:

[c] use The\Full\Namespace; (at the top of your source file) followed by $a = new CoolClass();

UPDATE: [c] является ошибкой и не так, как пространства имен работают в любом случае. Я могу сообщить, что вместо [c] также хорошо работают следующие два случая:

[d] use The\Full\Namespace; (at the top of your source file) followed by $a = new Namespace\CoolClass();

[e] use The\Full\Namespace\CoolClass; (at the top of your source file) followed by $a = new CoolClass();

надеюсь, что это помогает.

была та же проблема и просто нашел это :

при создании структуры вложенной папки, соответствующей пространствам имен содержащих классов, вам даже не придется определять автозагрузчик.

    spl_autoload_extensions(".php"); // comma-separated list
    spl_autoload_register();

это сработало как шарм

дополнительная информация здесь:http://www.php.net/manual/en/function.spl-autoload-register.php#92514

EDIT: это вызывает проблемы в Linux из-за обратной косой черты... См. здесь для рабочего решения мимо immeëmosol

пространство имен Autoload работает под windows, но не на Linux

использование имеет gotcha, хотя это, безусловно, самый быстрый метод, он также ожидает, что все ваши имена файлов будут строчными.

spl_autoload_extensions(".php");
spl_autoload_register();

например:

файл, содержащий класс SomeSuperClass, должен быть назван somesuperclass.php, это gotcha при использовании чувствительной к регистру файловой системы, такой как Linux, если ваш файл называется SomeSuperClass.php, но не проблема под Windows.

использование __autoload в коде все еще может работать с текущими версиями PHP, но ожидайте, что эта функция станет устаревшей и, наконец, будет удалена в будущем.

Итак, какие варианты остались:

эта версия будет работать с PHP 5.3 и выше и позволяет использовать имена файлов SomeSuperClass.php и somesuperclass.РНР. Если вы используете 5.3.2 и выше, этот загрузчик будет работать еще быстрее.

<?php

if ( function_exists ( 'stream_resolve_include_path' ) == false ) {
    function stream_resolve_include_path ( $filename ) {
        $paths = explode ( PATH_SEPARATOR, get_include_path () );
        foreach ( $paths as $path ) {
            $path = realpath ( $path . PATH_SEPARATOR . $filename );
            if ( $path ) {
                return $path;
            }
        }
        return false;
    }
}

spl_autoload_register ( function ( $className, $fileExtensions = null ) {
    $className = str_replace ( '_', '/', $className );
    $className = str_replace ( '\', '/', $className );
    $file = stream_resolve_include_path ( $className . '.php' );
    if ( $file === false ) {
        $file = stream_resolve_include_path ( strtolower ( $className . '.php' ) );
    }
    if ( $file !== false ) {
        include $file;
        return true;
    }
    return false;
});

Я недавно нашел ответ танеркука очень полезным! Просто хотел добавить, что с помощью strrpos() + substr() немного быстрее, чем explode() + end():

spl_autoload_register( function( $class ) {
    $pos = strrpos( $class, '\' );
    include ( $pos === false ? $class : substr( $class, $pos + 1 ) ).'.php';
});

Я брошу свои два цента для относительных новичков или чего-то еще, желая простой настройки spl_autoload_register () без всякой теории: Просто создайте один php-файл для каждого класса, назовите этот php-файл таким же, как и имя вашего класса, и сохраните файлы классов в том же каталоге, что и ваш php-файл, тогда это будет работать:

spl_autoload_register(function ($class_name) {
    require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . $class_name . '.php';
});

Googling части внутри этой функции должны ответить, как это работает. PS: я использую Linux, и это работает на Linux. Windows люди должны проверить его выходим первыми.

https://thomashunter.name/blog/simple-php-namespace-friendly-autoloader-class/

вы хотите поместить файлы классов в папку с именем Classes, которая находится в том же каталоге, что и точка входа в ваше PHP-приложение. Если классы используют пространства имен, пространства имен будут преобразованы в структуру каталогов. В отличие от многих других автопогрузчиков, подчеркивания не будут преобразованы в структуры каталогов (это сложно сделать PHP = 5.3 настоящих имен).

<?php
class Autoloader {
    static public function loader($className) {
        $filename = "Classes/" . str_replace("\", '/', $className) . ".php";
        if (file_exists($filename)) {
            include($filename);
            if (class_exists($className)) {
                return TRUE;
            }
        }
        return FALSE;
    }
}
spl_autoload_register('Autoloader::loader');

вы хотите поместить следующий код в ваш основной скрипт PHP (точка входа):

require_once("Classes/Autoloader.php");

вот пример макета каталога:

index.php
Classes/
  Autoloader.php
  ClassA.php - class ClassA {}
  ClassB.php - class ClassB {}
  Business/
    ClassC.php - namespace Business classC {}
    Deeper/
      ClassD.php - namespace BusinessDeeper classD {}

Я использую этот простой хак в одну строку:

spl_autoload_register(function($name){
        require_once 'lib/'.str_replace('\','/',$name).'.php';
    });
<?php
spl_autoload_register(function ($classname){
   // for security purpose
   //your class name should match the name of your class "file.php"
   $classname = str_replace("..", "", $classname);
   require_once __DIR__.DIRECTORY_SEPARATOR.("classes/$classname.class.php");
});
try {
  $new = new Class1();
} catch (Exception $e) {
   echo "error = ". $e->getMessage();
}
?>