자동로드와 함께 PHP 네임 스페이스를 어떻게 사용합니까?


104

자동로드 및 네임 스페이스를 사용하려고하면이 오류가 발생합니다.

치명적인 오류 : 10 행의 /usr/local/www/apache22/data/public/php5.3/test.php 에서 'Class1'클래스를 찾을 수 없습니다.

아무도 내가 뭘 잘못하고 있는지 말해 줄 수 있습니까?

내 코드는 다음과 같습니다.

Class1.php :

<?php

namespace Person\Barnes\David
{
    class Class1
    {
        public function __construct()
        {
            echo __CLASS__;
        }
    }
}

?>

test.php :

<?php

function __autoload($class)
{
    require $class . '.php';
}

use Person\Barnes\David;

$class = new Class1();

?>

답변:


119

Class1은 전역 범위에 없습니다.

작동 예는 아래를 참조하십시오.

<?php

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

use Person\Barnes\David as MyPerson;

$class = new MyPerson\Class1();

편집 (2009-12-14) :

명확히하기 위해 "use ... as"를 사용하여 예제를 단순화했습니다.

대안은 다음과 같습니다.

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

또는

use Person\Barnes\David\Class1;

// ...

$class = new Class1();

1
을 사용할 필요가 없습니다 AS. 이것이이 솔루션이 작동하는 이유가 아닙니다. 당신은 쉽게 할 수있는 : use Person\Barnes\David\Class1;(에 해당한다 use Person\Barnes\David\Class1 as Class1;).
cartbeforehorse 2013 년

1
감사합니다. 작동합니다. 하지만 왜 우리가 $ class = new Class1 (); "use Person \ Barnes \ David;"를 이미 정의한 경우?
user345602

4
@ 사용합니다 user346665 use Person\Barnes\David\Class1;수행하려면 $class = new Class1();. use Person\Barnes\David;당신 과 함께 해야합니다 $class = new David\Class1();. use자체 키워드의 동등 use Person\Barnes\David\Class1 as Class1;또는 use Person\Barnes\David as David;각 예컨대 각각.
Justin C

2018 년 독서의 경우 spl_autoload_register와 함께 @ prince-billy-graham 솔루션을 사용하세요
Bruno de Oliveira

26

Pascal MARTIN에서 언급했듯이 '\'를 DIRECTORY_SEPARATOR로 바꿔야합니다. 예를 들면 다음과 같습니다.

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

또한 코드를 더 읽기 쉽게 만들기 위해 디렉토리 구조를 재구성하는 것이 좋습니다. 이것은 대안이 될 수 있습니다.

디렉토리 구조 :

ProjectRoot
 |- lib

파일: /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 권장 사항을 사용했습니다. 여전히 PHP 4를 사용하는 경우 이전 구문으로 바꾸십시오. function __autoload ($ class)

18

귀하의 __autoload기능은 네임 스페이스 이름을 포함한 전체 클래스 이름을 받게됩니다.

즉, 귀하의 경우 __autoload함수는 ' Person\Barnes\David\Class1'뿐만 아니라 ' Class1'를 수신합니다.

따라서 "더 복잡한"이름을 처리하려면 자동 로딩 코드를 수정해야합니다. 자주 사용되는 솔루션은 네임 스페이스의 "수준"당 한 수준의 디렉터리를 사용하여 파일을 구성하고, 자동로드 할 때 \네임 스페이스 이름의 ' '를 DIRECTORY_SEPARATOR.


1
이것은 내가 찾은 것이 아닙니다. 내가 문장을 넣었을 때 die ($ class); __autoload 함수에서 'Person \ Barnes \ David \ Class1'이 아니라 'Class1' '을 출력했습니다.
David Barnes

진실. autoload의 $ class 매개 변수는 생성자 호출에서 작성된 클래스 이름입니다.
tishma 2013

1
"당신의 __autoload함수는 네임 스페이스 이름을 포함한 전체 클래스 이름을받을 것 입니다. "에 대한 반대 투표 -이것은 use당신이 참조하려는 클래스를 명시 적으로 정의한 경우에만 해당되며 , use그것이 속한 네임 스페이스 가 아니라면 해당 됩니다. OP의 실수는 그가 use클래스를 포함하는 네임 스페이스를 만들었고 그의 자동로드 기능이 어떻게 든 마법처럼 전체 클래스 경로를 통과 할 것으로 기대하고 있었다는 것입니다. 이 답변은 실제로 OP의 실수를 해결하지 않습니다.
Mark Amery 2014

15

다음과 같이합니다 : 이 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___
}

3
멋지고 간단합니다. .)
dennis

3

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);
    }
});

3

자동로드 함수는 다음 두 가지 경우에만 "전체"클래스 이름 (앞에있는 모든 네임 스페이스 포함)을받습니다.

[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();

업데이트 : [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();

도움이 되었기를 바랍니다.


참고로 use키워드는 PHP 대화 형 명령 줄 인터페이스 ( php --interactive) 에서 제대로 작동하지 않습니다 .
Andrew Larsson

3

이 간단한 해킹을 한 줄로 사용합니다.

spl_autoload_register(function($name){
        require_once 'lib/'.str_replace('\\','/',$name).'.php';
    });

1

같은 문제가 있었고 방금 이것을 발견했습니다.

포함하는 클래스의 네임 스페이스와 일치하는 하위 폴더 구조를 만들 때 자동 로더를 정의 할 필요조차 없습니다.

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

매력처럼 작동 했어

여기에 더 많은 정보 : http://www.php.net/manual/en/function.spl-autoload-register.php#92514

편집 : 이것은 백 슬래시 때문에 Linux에서 문제를 일으 킵니다 ... immeëmosol의 작업 솔루션은 여기를 참조하십시오.

네임 스페이스 자동로드는 Windows에서 작동하지만 Linux에서는 작동하지 않습니다.


1

을 사용하는 것이 가장 빠른 방법이지만 모든 파일 이름이 소문자 일 것으로 예상합니다.

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

예를 들면 :

SomeSuperClass 클래스를 포함하는 파일은 somesuperclass.php로 이름을 지정해야합니다. Linux와 같은 대소 문자 구분 파일 시스템을 사용할 때 파일 이름이 SomeSuperClass.php이지만 Windows에서는 문제가되지 않는 경우이 문제가 발생합니다.

코드에서 __autoload를 사용하면 현재 버전의 PHP에서 계속 작동 할 수 있지만이 기능은 더 이상 사용되지 않고 나중에 제거 될 것으로 예상됩니다.

따라서 남은 옵션 :

이 버전은 PHP 5.3 이상에서 작동하며 SomeSuperClass.php 및 somesuperclass.php 파일 이름을 허용합니다. 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;
});

2
보조 노트로, str_replace ([ '_','\\'] '/', $className );보다 세 배 이상 빠른 속도로 두 개의 않는 str_replace입니다
Itay Moav -Malimovka

php 파일이 대문자 / 소문자인지 여부가 중요하지 않은 한, 디렉토리는 여전히 대소 문자를 구분합니다
Mike

1

최근에 tanerkuc의 답변이 매우 유용하다는 것을 알았습니다! strrpos()+ 를 사용하는 substr()것이 explode()+ 보다 약간 빠르다는 것을 추가하고 싶었습니다 end().

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

1

나는 상대적인 초보자 또는 모든 이론이없는 간단한 spl_autoload_register () 설정을 원하지 않는 경우에 2 센트를 투자 할 것입니다. 각 클래스에 대해 하나의 PHP 파일을 만들고 해당 PHP 파일의 이름을 클래스 이름과 동일하게 지정하고 클래스 파일을 유지합니다. 문제의 PHP 파일과 동일한 디렉토리에 있으면 다음과 같이 작동합니다.

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

이 함수 내부의 조각을 검색하면 작동 방식에 대한 답을 얻을 수 있습니다. 추신 : 저는 Linux를 사용하며 이것은 Linux에서 작동합니다. Windows 사용자는 먼저 테스트해야합니다.


1

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

ClassesPHP 애플리케이션의 진입 점과 동일한 디렉토리에있는 라는 폴더에 클래스 파일을 넣을 수 있습니다 . 클래스가 네임 스페이스를 사용하는 경우 네임 스페이스는 디렉터리 구조로 변환됩니다.

다른 많은 자동 로더와 달리 밑줄은 디렉토리 구조로 변환되지 않습니다 (PHP> = 5.3 실제 네임 스페이스와 함께 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 Business\Deeper; classD {}

0
<?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();
}
?>

1
이 코드가 질문에 답할 수는 있지만이 코드가 질문에 대한 답변 이유 및 / 또는 방법에 대한 추가 컨텍스트를 제공하면 장기적인 가치가 향상됩니다.
Ethan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.