PHP ad alanlarını otomatik yüklemeyle nasıl kullanırım?


104

Otomatik yüklemeyi ve ad alanlarını kullanmaya çalıştığımda şu hatayı alıyorum:

Önemli hata: Sınıfı 'Sınıf1' bulunmayan /usr/local/www/apache22/data/public/php5.3/test.php üzerinde hat 10

Biri bana neyi yanlış yaptığımı söyleyebilir mi?

İşte kodum:

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

?>

Yanıtlar:


119

Class1 genel kapsamda değil.

Çalışan bir örnek için aşağıya bakın:

<?php

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

use Person\Barnes\David as MyPerson;

$class = new MyPerson\Class1();

Düzenleme (2009-12-14):

Sadece açıklığa kavuşturmak için, benim "kullanım ... gibi" kullanımım, örneği basitleştirmek içindi.

Alternatif şuydu:

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

veya

use Person\Barnes\David\Class1;

// ...

$class = new Class1();

1
Kullanmak zorunda değilsin AS. Bu çözümün işe yaramasının nedeni bu değil. Aynı şekilde kolayca yapabilirsiniz: use Person\Barnes\David\Class1;(eşdeğerdir use Person\Barnes\David\Class1 as Class1;).
cartbeforehorse

1
Teşekkürler, bu çalışıyor. Ama neden sadece $ class = new Class1 (); daha önce "Person \ Barnes \ David; kullan" ifadesini zaten tanımladığımızda?
user345602

4
@ user346665 use Person\Barnes\David\Class1;yapmak için kullanmanız gerekir $class = new Class1();. İle use Person\Barnes\David;size yapmanız gerekir $class = new David\Class1();. useTek başına kelime eşdeğerdir use Person\Barnes\David\Class1 as Class1;ya da use Person\Barnes\David as David;her örnek için, sırasıyla.
Justin C

2018'de okuyanlar için, spl_autoload_register ile @ prince-billy-graham çözümünü kullanın
Bruno de Oliveira

26

Pascal MARTIN'den bahsedildiği gibi, "\" karakterini DIRECTORY_SEPARATOR ile değiştirmelisiniz, örneğin:

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

Ayrıca kodu daha okunaklı hale getirmek için yönlendirici yapıyı yeniden düzenlemenizi öneririm. Bu bir alternatif olabilir:

Dizin yapısı:

ProjectRoot
 |- lib

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

<?php
namespace Person\Barnes\David
class Class1
{
    public function __construct()
    {
        echo __CLASS__;
    }
}
?>
  • Tanımladığınız her ad alanı için alt dizini oluşturun.

Dosya: /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();
  • Otomatik yükleyici bildirimi için php 5 önerisini kullandım. Hala PHP 4 kullanıyorsanız, onu eski sözdizimiyle değiştirin: function __autoload ($ class)

18

Sizin __autoloadişlevi ad adı dahil, tam sınıf adını alacaktır.

Bu, sizin durumunuzda, __autoloadişlevin Person\Barnes\David\Class1yalnızca ' Class1' değil ' ' alacağı anlamına gelir .

Bu nedenle, bu tür "daha karmaşık" adlarla başa çıkmak için otomatik yükleme kodunuzu değiştirmeniz gerekir; Sık kullanılan bir çözüm, dosyalarınızı ad alanlarının her "düzeyi" için bir dizin düzeyi kullanarak düzenlemek ve otomatik yüklerken \, ad alanı adındaki ' ' yerine DIRECTORY_SEPARATOR.


1
Bulduğum bu değil. İfadeyi koyduğumda die ($ class); __autoload işlevinde, 'Person \ Barnes \ David \ Class1' değil 'Class1 "' yazdırıldı
David Barnes

Doğru. autoload'ın $ class parametresi, yapıcı çağrısında yazıldığı şekliyle sınıf adıdır.
tishma

1
"__autoload İşleviniz , ad alanı adı da dahil olmak üzere tam sınıf adını alacak " için olumsuz oy verin - bu yalnızca usebaşvurmaya çalıştığınız sınıfı açıkça belirlediyseniz doğrudur, yalnızca useait olduğu ad alanını seçtiyseniz değil . OP'nin hatası, usebir sınıf içeren ad alanında olması ve ardından otomatik yükleme işlevinin sihirli bir şekilde tüm sınıf yolunu bir şekilde geçmesini beklemesiydi. Bu cevap, OP'nin hatasını gerçekten ele almıyor.
Mark Amery

15

Bunun gibi bir şey yapıyorum: Bu GitHub Örneğine bakın

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
Güzel ve basit. Eğer biri onu arıyor olmalı.)
dennis

3

Bu mücevheri Flysystem'den buldum

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ğıdaki iki durumda, otomatik yükleme işlevlerinin yalnızca "tam" sınıf adını aldığını görüyorum - tüm ad alanları ondan önce gelir:

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

Aşağıdaki durumda otomatik yükleme işlevlerinin tam sınıf adını ALMADIĞINI görüyorum:

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

GÜNCELLEME: [c] bir hatadır ve zaten ad alanlarının nasıl çalıştığı değildir. [C] yerine aşağıdaki iki durumun da işe yaradığını bildirebilirim:

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

Bu yardımcı olur umarım.


Bir yan not olarak, useanahtar kelime PHP etkileşimli komut satırı arayüzünde ( php --interactive) düzgün çalışmaz ;
Andrew Larsson

3

Bu basit hack'i tek satırda kullanıyorum:

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

1

aynı sorunu yaşadı ve şimdi şunu buldum:

İçeren sınıfların ad alanlarıyla eşleşen bir alt klasör yapısı oluşturduğunuzda, bir otomatik yükleyici tanımlamanız bile gerekmez.

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

Bir cazibe gibi çalıştı

Daha fazla bilgi burada: http://www.php.net/manual/en/function.spl-autoload-register.php#92514

DÜZENLEME: bu, Linux'ta ters eğik çizgi nedeniyle soruna neden oluyor ... immeëmosol'un çalışma çözümü için buraya bakın

Ad Alanı Otomatik Yükleme, Windows altında çalışır, ancak Linux'ta çalışmaz


1

Has a gotcha kullanmak, en hızlı yöntem olsa da, tüm dosya adlarınızın küçük harf olmasını bekler.

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

Örneğin:

SomeSuperClass sınıfını içeren bir dosyanın somesuperclass.php olarak adlandırılması gerekir, bu, Linux gibi büyük / küçük harfe duyarlı bir dosya sistemi kullanırken, eğer dosyanız SomeSuperClass.php olarak adlandırılmışsa ancak Windows altında bir sorun değilse, bir gotcha'dır.

__Autoload'u kodunuzda kullanmak PHP'nin mevcut sürümleriyle hala çalışabilir, ancak bu özelliğin kullanımdan kaldırılmasını ve gelecekte de kaldırılmasını bekleyin.

Öyleyse hangi seçenekler kaldı:

Bu sürüm PHP 5.3 ve üstü ile çalışacak ve SomeSuperClass.php ve somesuperclass.php dosya isimlerine izin verecektir. 5.3.2 ve üstünü kullanıyorsanız, bu otomatik yükleyici daha da hızlı çalışacaktır.

<?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
bir yan not olarak, str_replace ([ '_','\\'] '/', $className );iki kat daha hızlı str_replace
Itay Moav -Malimovka

Php dosyasının büyük / küçük harfli olup olmadığı önemli olmadığı sürece, dizinler büyük / küçük harf duyarlı olmaya devam eder
Mike

1

Geçenlerde tanerkuç'un cevabını çok faydalı buldum! Sadece kullanarak eklemek istedim strrpos()+ substr()biraz daha hızlıdır explode()+ end():

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

1

Göreceli yeni başlayanlar için veya tüm teori olmadan basit bir spl_autoload_register () kurulumu istemeyenler için iki sentimi atacağım: Her sınıf için sadece bir php dosyası oluşturun, bu php dosyasını sınıf adınızla aynı şekilde adlandırın ve sınıf dosyalarınızı saklayın söz konusu php dosyanızla aynı dizinde, o zaman bu çalışacaktır:

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

Bu işlevin içindeki parçaları araştırmak, nasıl çalıştığını yanıtlamalıdır. Not: Linux kullanıyorum ve bu Linux'ta çalışıyor. Windows millet önce onu test etmelidir.


1

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

Sınıf dosyalarınızı Classes, PHP uygulamanızın giriş noktasıyla aynı dizinde bulunan adlı bir klasöre koymak isteyeceksiniz . Sınıflar ad alanları kullanırsa, ad alanları dizin yapısına dönüştürülür.

Diğer birçok otomatik yükleyicinin aksine, altçizgiler dizin yapılarına dönüştürülmez (PHP> = 5.3 gerçek ad alanları ile birlikte PHP <5.3 sözde ad alanları yapmak zordur).

<?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');

Aşağıdaki kodu ana PHP betiğinize (giriş noktası) yerleştirmek isteyeceksiniz:

require_once("Classes/Autoloader.php");

Örnek bir dizin düzeni aşağıda verilmiştir:

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
Bu kod soruyu yanıtlayabilirken, bu kodun soruyu neden ve / veya nasıl yanıtladığına ilişkin ek bağlam sağlamak, uzun vadeli değerini artırır.
Ethan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.