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.