2013年5月29日 星期三

關於 載入 Class

關於 載入 Class 的進化史
自從程式寫作方式轉換至 Class 的開發方式
就慢慢的將各功能寫成 Class , 也都將各 Class 存成獨立的檔案
例: Corder.php , class.order.php 等檔案命名方式
隨著類別產生各自的檔案,也在程式執行時,載入該頁面所需要執行的 Class


require("class.file1.php") ;
require("class.file2.php") ;
require_once("class.file3.php") ;   //  為了防止重覆載入,所以多了 _once 

//這樣就可以快快樂樂的使用 Class

$obj = new file1();
$obj->sayhi();

後來,慢慢的,程式越寫越大,越寫越複雜,越寫層次越多
因為,越寫越亂了....
也因此要載入的 Class 也越來越多


require("class.file1_base.php") ;
require("class.file1.php") ;
require("class.file1_ext1.php") ;
require("class.file1_ext2.php") ;
require("forder1\class.file2.php") ;
require("forder2\class.file3_base.php") ;
require("forder3\sub1\class.file3_ext1.php") ;

光寫以上7行,就感覺很難管理,更別說,更大更複雜功能,需載入來自世界各地的 Class
還好,為了防止Class沒有載入,所以我用了 class_exists 先判斷一下


if (@class_exists($wannt_class))
{
    require_once($wannt_class . '.php');
}

雖然這樣子寫,有多一個判斷,但還是要載入來自世界各地的 Class 檔案
於是,就有了 __autoload()


function __autoload($class_name) {
    include $path . $class_name . '.php';
}

$obj  = new MyClass1();
$obj2 = new MyClass2(); 

//再加上 try catch 

function __autoload($name) {
    echo "Want to load $name.\n";
    throw new Exception("Unable to load $name.");
}

try {
    $obj = new NonLoadableClass();  //  宣告一個不存在的 Class
} catch (Exception $e) {
    echo $e->getMessage(), "\n";
}

不過,這個會有些問題,__autoload 程式一執行,就會執行的函式
那麼,如果我要自己指定載入的時間點,及變更 function 的名稱,可以嗎?
答案是,可以的,利用 spl_autoload_register


function my_autoloader($class) {
    include 'classes/' . $class . '.class.php';
}

spl_autoload_register('my_autoloader');

// Or, using an anonymous function as of PHP 5.3.0
spl_autoload_register(function ($class) {
    include 'classes/' . $class . '.class.php';
});

也可以在 Class 裡面新增一個 autoload  的 function
然後,在執行該 Class 時,再進行載入相關  Class


class MyClass {
  public static function autoload($className) {
    // ...
  }
}

spl_autoload_register(array('MyClass', 'autoload'));

// Or you can use an instance :

class MyClass {
  public function autoload($className) {
    // ...
  }
}

$instance = new MyClass();
spl_autoload_register(array($instance, 'autoload'));

稍為整理一下....


spl_autoload_register(function($class) {
    if(file_exists($class.'.php'))
    {
        include $class.'.php';

        if (!class_exists($class))
        {
            die('required class not present');
        }
    }
    else
    {
        die('file not found');
    }
});

最後,再整理出自己的版本,附加使用 include_path


define('DOC_ROOT', dirname(__FILE__)) ;     //定義該專案根目錄位置
define('LIB_PATH', DOC_ROOT. '\lib') ;      //定義共用LIB資料夾位置
define('CLASS_PATH', DOC_ROOT. '\class') ;  //定義類別存放置置

//  增加 include_path 於設定值
$_inc_path = '';
//$_inc_path .= CLASS_PATH . PATH_SEPARATOR ;    //存放類別目錄
$_inc_path .= LIB_PATH . '\activerecord\lib'. PATH_SEPARATOR ;   // activerecord(ORM)函式目錄
ini_set('include_path', $_inc_path . ini_get('include_path')) ;
//ini_set('error_log', dirname(__FILE__) . '/data/error_log.txt');  //設定 error_log 記錄至檔案

//利用 匿名函式 註冊 autoload func.
spl_autoload_register(function ($class_name) {
    $class_file = $class_name . '.php' ;
    @include_once($class_file) ;    //不能使用 require , 因為 require 如果沒有檔案,程式會中斷
    
    if ( !class_exists($class_name) ) {
        echo "no class.";
        throw new Exception ("Unable to load $class_name.");
    }else{
        echo "class exists;";
    }
    
    //  基本上,如果在 include_path 都有設定好,是不用 file_exist
    /*
    if( file_exists($class_file) ) 
    {    
        require_once($class_file) ;    
    } else {
        throw new Exception("Unable to load $class_name.");
    }
    */
});

try {
    $obj = new myClass();
    $obj->sayhi();
}catch(Exception  $e){
    echo $e->getMessage(), "\n";

}



沒有留言:

張貼留言