__ Autoload için en iyi çözüm

10 Cevap php

Bizim PHP5 OO uygulaması (büyüklüğü ve trafik hem de) büyüdükçe, biz __ autoload () stratejisini tekrar karar verdi.

Biz her zaman içerdiği sınıf tanımı ile dosyayı adlandırın, böylece sınıf Müşteri Customer.php içinde yer olacaktır. Doğru. Php dosya bulundu kadar biz, bir dosya potansiyel var hangi dizinleri listelemek için kullanılır.

Eğer stat (yükleri () çağrıları yapmak, böylece) potansiyel olarak gerekmez dizinleri bir dizi geçiyor ve her istek üzerine bunu yapıyoruz, çünkü bu, oldukça verimsiz.

Benim akla gelen çözümler ...

(PEAR benzer) dizin adını belirleyen bir adlandırma kuralı kullanmayın. Dezavantajları: korkunç sınıf isimlerinde sonuçlanan, çok büyük ölçekli değildir.

Yerlerde (propel onun __ autoload için yapar) öncesi inşa edilen dizinin çeşit ile-geliyor. Dezavantajı: Yeni bir kodun herhangi dağıtmadan önce yeniden gerektirir.

"Fly" dizi-inşa ve önbelleğe. Bu istediğiniz herhangi bir sınıf adları ve dizin yapısı için izin verir, ve sadece listesine eklenir olsun yeni dosyalar tamamen esnek olduğu gibi, en iyi çözüm gibi görünüyor. Endişeleri vardır: silinen / taşınan dosyalar hakkında saklamak ve ne nerede. Bu disk I / O yükünü yok gibi depolama için biz, APC seçtik. Saygılarımızla siler dosya ile muhtemelen istiyorsun yerde onları zaten ihtiyaç yok gibi, o, önemli değil. Hamle olarak ... (biz tarihsel bizim için çok sık olmadı olarak görmezden) çözümlenmemiş bulunuyor.

Başka bir çözüm?

10 Cevap

Ben de oldukça uzun bir süre için autoload ile oynuyorum ve ben (evet, o PHP5.2 için de çalışıyor) alanlı autoloader çeşit uygulama sona erdi.

The strategy is quite simple: First I have a singleton class (loader) which has a call that simulates import. This call takes one parameter (the full class name to load) and internally calculates the file name it was called from (using debug_backtrace()). The call stores this information in an associative array to use it later (using the calling file as the key, and a list of imported classes for each key).

Tipik kod şöyle görünür:

<?php

    loader::import('foo::bar::SomeClass');
    loader::import('foo::bar::OtherClass');

    $sc = new SomeClass();

?>

Özdevinimli_yükle ateş edildiğinde, dizide depolanan tam sınıf adı gerçek bir dosya sistemi konumu (çift iki nokta üst üste dizin ayracı ile değiştirilir) dönüştürülmüş olur ve çıkan dosya adı dahildir.

Ben Size soran ne tam olarak değil biliyorum, ama dosya tam olarak hiçbir belirgin performansı ile, sizin sınıfları dizinleri düzenlenen olabilir ekledi özelliği ile (nerede yükleyici doğrudan bildiği gibi, dizin geçişi sorunu çözebilir ceza).

Ben size bazı çalışma örneklerini verebilir, ama ben halka benim rezil kodunu göstermek için çok utangaç değilim. Yukarıdaki açıklama yararlı olmuştur umarım ...

There is 2 general approaches that work well.
First is using PEAR standard class naming structure so you just need to replace '_' with / to find the class.

http://pear.php.net/manual/en/pear2cs.rules.php

Or you can search directories for php classes and map class name to file. You can save the class map to cache to save searching directories every page load.
Symfony framework uses those approach.

Genel olarak daha iyi daha basit olarak standart yapıyı takip etmek ve bir şey önbelleğe gerekmez, ayrıca daha sonra önerilen kurallar şunlardır.

Biz gerektiren önce () kontrol edin, bir file_exists hariç, çok son seçenek gibi bir şey kullanabilirsiniz. O yoksa, önbelleğini yeniden ve bir kez daha deneyin. Dosya başına ekstra Stat olsun, ama şeffaf hamle işler. Ben taşımak veya sık sık şeyleri adlandırmak hızlı gelişimi için çok kullanışlı.

Ben geçmişte bu çözümü kullanmış, ben referans için bu konuda blogged ve size bazı ilginç olabilir ...

Here it is

CodeIgniter load_class fonksiyonu ile benzer bir şey yapar. Eğer doğru hatırlıyorsam, bu nesneleri dizisi tutan statik bir fonksiyondur. Işlevine çağrı:


 load_class($class_name, $instansiate);

böylece durumda


 load_class('Customer', TRUE);

ve bu nesneler diziye Müşteri sınıfının bir örneği yüklemek olacaktır.

Fonksiyon ileri oldukça düz oldu. Üzgünüm içeri olduğu sınıfın adını hatırlayamıyorum Ama ben gibi yüklü olsun çeşitli sınıfları Bence olduğunu hatırlamıyorum yok Yönlendirme sınıf, Benchmark sınıf ve URI sınıf.

APC kullanıyorsanız ediyorsanız, opcode önbelleğe etkinleştirmeniz gerekir. Ben bu performansı daha fazla fayda var, ve istihdam herhangi bir sınıf / dosya strateji daha şeffaf bir çözüm olacağına inanıyorum.

İkinci öneri karşı en kolay geliştirmek için ne olursa olsun sınıf / dosya strateji kullanmak için, ancak üretim yerinde, tek bir dosya içine en sık kullanılan sınıfları birleştirmek ve her istek (veya APC ile önbelleğe alınmış) sırasında yüklenen emin olun gerektiğidir.

Kendi sınıflarının artan setleri ile bazı performans deneyleri yapmak. Muhtemelen dosya I / O azaltmak yararı her istek sırasında tüm sınıfları gerekmez bile, tek bir dosya içine birlikte tüm sınıfları doldurma net kazanmak olduğunu, bu nedenle önemli olduğunu göreceksiniz.

Ben sınıfın her 'tür' için özel adlandırma kuralları var (kontrolörleri, böylece modeller, kütüphane dosyaları, ve ...), yani şu anda ben benzer bir şey:

function __autoload($class){
    if($class matches pattern_1 and file_exists($class.pattern_1)){
        //include the file somehow
    } elseif($class matches pattern_2 and file_exists($class.pattern_2)){
        //include the file somehow
    } elseif(file_exists($class.pattern_3)){
        //include the file somehow
    } else {
       //throw an error because that class does not exist?
    }
}

Eski diş ama ben belki biri yardımcı olabilir, zaten burada benim yöntemi açığa düşündüm. Bu web siteme giriş noktası /path/to/root/www/index.php, örneğin in __autoload() tanımlamak yoludur:

function __autoload($call) {
    require('../php/'.implode('/', explode('___', $call)).'.php');
}

Tüm PHP dosyaları bir ağaç organize olan

/path/to/root/php
  /Applications
    /Website
      Server.php
  /Model
    User.php
  /Libraries
    /HTTP
      Client.php
    Socket.php

Ve sınıflar isim vardır:

Applications___Website___Server
Model___User
Libraries___HTTP___Client
Libraries___Socket

Bu hızlı ve dosya mevcut değilse, o zaman kilitlenmesine ve hata günlüğü eksik olduğu dosya size söyleyecektir. Bu biraz sert görünebilir ama yanlış sınıfını kullanmayı denerseniz, bu senin sorunun.

NB: PHP 5 oldu < PHP 5.3 için siz ad kullanabilirsiniz yani 5.3, ben ayırıcı olarak _ 3 kullanılan neden nedeni 5.3 ad kullanımı için yapmak kolay bir yedek olduğunu

Eğer Zend_Loader yerine sadece yerli (registerAutoload() ile) kullanılarak araştırılmıştır __autoload()? Ben Zend_Loader kullandım ve onunla mutlu olmuştur, ancak bir performans açısından ona bakmadım. Ancak, this blog post üzerinde bazı performans analizi yapmış gibi görünüyor; Eğer beklentilerinizi karşılayacak olmadığını görmek için geçerli autoloader üzerinde içi performans testi için bu sonuçları karşılaştırabilirsiniz.

function __autoload( $class )
{
    $patterns = array( '%s.class.php', '%s.interface.php' );

    foreach( explode( ';', ini_get( 'include_path' ) ) as $dir )
    {
        foreach( $patterns as $pattern )
        {
            $file    = sprintf( $pattern, $class );
            $command = sprintf( 'find -L %s -name "%s" -print', $dir, $file );
            $output  = array();
            $result  = -1;

            exec( $command, $output, $result );

            if ( count( $output ) == 1 )
            {
                require_once( $output[ 0 ] );
                return;
            }
        }
    }

    if ( is_integer( strpos( $class, 'Exception' ) ) )
    {
        eval( sprintf( 'class %s extends Exception {}', $class ) );
        return;
    }

    if ( ! class_exists( $class, false ) )
    {
    	// no exceptions in autoload :(
        die( sprintf( 'Failure to autoload class: "%s"', $class ) );
        // or perhaps: die ( '<pre>'.var_export( debug_backtrace(), true ).'</pre>' );        
    }
}

Ayrıca dizinleri yinelemek için bazı diğer POSIX bağımlı yol bulabiliriz, ama bu kullanarak oldum budur.

Bu bir sınıf veya arayüz bulmak için tüm (php.ini içinde ya. Htaccess) include_path dizinleri erişir.