代码之家  ›  专栏  ›  技术社区  ›  Timo Huovinen

php:在可选文件中高效地运行一次性加载类的函数

  •  0
  • Timo Huovinen  · 技术社区  · 15 年前

    在阅读了答案之后,我重写了我的问题。

    假设我有一个理论上的PHP应用程序,它使用做不同事情的对象。 对于应用程序加载的每个页面,将运行不同的脚本。

    现在我制作了一个简单的PHP脚本,创建了一个简单的对象。 (这都是编造的,我只是想在编代码之前理解它)

    $user = new userClass($db);
    $user->login($credentials);
    

    一切都很好,我甚至可以在创建用户类之后重复这个过程几次

    $user = new userClass($db);
    $user->login($credentials);
    ...
    $user->login($credentials2);
    

    现在想象一下,如果这两个部分被分成两个不同的PHP文件。

    file1:
    $user = new userClass($db);
    $user->login($credentials);
    file2:
    $user->login($credentials2);
    
    include file1
    include file2
    

    如果按顺序运行,那么一切都可以,但是如果没有,或者如果根本不包括file1…

    file2:
    $user->login($credentials);
    file1:
    $user = new userClass($db);
    $user->login($credentials2);
    
    include file2
    include file1
    

    那它就不起作用了…它们必须保持顺序,所以让我们创建一个主PHP文件,不管加载什么。

    main file:
    $user = new userClass($db);
    file1:
    $user->login($credentials);
    file2:
    $user->login($credentials2);
    

    (例如,包括自动加载的文件) 包括主要 包含文件1 包含文件2 或 包括主要 包含文件2 包含文件1 或 包括主要 包含文件2

    现在,文件1和2可以按任意顺序加载,其中一个不依赖于另一个,但是如果文件1和文件2都是不必要的呢?

    main file:
    $user = new userClass($db);
    //nothing else gets loaded
    

    那么,主文件也是不必要的,并且将被证明是一个资源占用者,当然,如果它的一个类没有问题,但是如果主文件加载了数百个从未使用过的类呢?

    一点也不优雅。

    然后,让我们尝试另一种方式,让我们完全废弃主文件,然后这样做(下面是我想要实现的目标的基本示例):

    file1:
    if(!is_object($user)){
        $user = new userClass($db);
    }
    $user->login($credentials);
    file2:
    if(!is_object($user)){
        $user = new userClass($db);
    }
    $user->login($credentials2);
    

    当然可以,但它不优雅,现在是吗?

    让我们试试方法重载…

    class loader {
       private $objects;
       private $db;
       function __construct($db){
          $this->objects = array();
          $this->db = $db;
       }
       function __get($name){
          if(!isset($this->objects[$name])){
             return $this->objects[$name] = new $name($this->db);
          }
       }
    }
    
    main file:
    $loader = new loader($db);
    file1:
    $loader->user->login($credentials);
    file3:
    $loader->user->login($credentials3);
    file2:
    $loader->user->login($credentials2);
    file4:
    $loader->user->login($credentials4);
    

    似乎可以工作,直到你意识到你不能再给任何以这种方式创建的对象任何其他变量,除了$db。 这意味着加载器类仅限于与用户类一起使用(例如) 因为将加载器类与任何其他类一起使用将需要编辑加载器类

    简单的脚本如下:

    $user = new userClass($this->db);
    $user->login($credentials);
    $form = new formClass($_POST);
    $form->process($info);
    

    将需要两个单独的加载程序类或加载程序类中至少两个方法

       class loader {
           private $objects;
           private $db;
           function __construct($db){
              $this->objects = array();
              $this->db = $db;
           }
           function getuserclass($name){
              if(!isset($this->objects[$name])){
                 return $this->objects[$name] = new $name($this->db);
              }
           }
           function getformclass($name){
              if(!isset($this->objects[$name])){
                 return $this->objects[$name] = new $name($_POST);//just an unrealistic example.
              }
           }
        }
    
    main file:
    $loader = new loader($db);
    file1:
    $loader->getuserclass('user')->login($credentials);
    file3:
    $loader->getformclass('form')->process($info);
    

    但这也不优雅。

    这是怎么回事 真正地 应该完成吗?

    3 回复  |  直到 15 年前
        1
  •  1
  •   Finbarr    15 年前

    这可能对你有用:

    class loader {
       private $objects;
    
       function __construct(){
          $this->objects = array();
       }
    
       function __call($name, $args){
          if(!isset($this->objects[$name])){
             return $this->objects[$name] = new $name($args);
          }
       }
    }
    $loader = new loader();
    
    $user = $loader->user($db);
    $form = $loader->form($form_args);
    

    如果您需要多个实例,您可以在每个对加载器的调用中包含一个附加的第一个参数(名称),并更改加载器代码以使用第一个参数作为对象的键,然后将其余的参数传递给对象的构造函数。

        2
  •  0
  •   GrandmasterB    15 年前

    在我看来,这就是为什么通过应用程序使用include()是一个坏主意,并且会造成严重的维护难题。尤其是对于不熟悉代码的人。他们可能会在两年后打开一个PHP文件并看到一个变量…不知道它是什么,也不知道它是在哪里初始化的。

    如果你遇到这种问题,你的应用程序的基本结构可能需要重做。一个更好的方法来组织你的应用程序是把所有的includes放在你的应用程序的顶部,这样你就不会对包括哪些文件或者它们被包括的顺序产生歧义。然后使用模板系统来控制输出。不要使用“includes()”以内联方式插入代码。使用它们来代替C include。您所包含的文件应该包含函数和类,并且在全局范围内运行的代码很少(如果有的话)。

    这样做,我想你会发现你不会再遇到这些问题了。

        3
  •  0
  •   Plokko    15 年前

    只需使用自动装载机和单点模式: 创建一个类,将所有类(例如/modules/)与包含的类同名,只记住声明。

    现在将此代码(在“主文件”中)包含在所有页面的顶部:

    function __autoload($class_name) {
        if(!ctype_alnum(str_replace(array('-','_'), '',$class_name)))//filename check,security reasons
            die('Module name not valid! ');
        require_once 'modules/'.$class_name.'.php';//load the class
    }
    

    您可能想要创建一个单例类(它是一个对象模式,它基本上确保类中只存在一个实体)

    文件:userclass.php

    <?php
    class UserClass{
        private static $istance=null;
        private function UserClass($db){
            //your constructor code here
        };
        private static function getIstance($db){//you can call it init($db) and create a getInstace() that only return the instance,i prefer that way,do as you want.
            if($istance==null)
                $istance=new UserClass($db);
            return $istance;
        };
        function login($credentials){
                //....
        }
        //...other functions...
    }
    ?>
    

    现在要使用它,您可以这样做:

    require 'main.php';//require the autoloader
    $user=UserClass::getIstance($db);//the class file will be automatically included and a new istance will be created
    $user->login($credentials1);
    $user->login($credentials2);
    $user=UserClass::getIstance($db);//no new istance will be created,only returned
    $user->login($credentials3);
    $user2=UserClass::getIstance($db);//no new istance will be created,only returned
    $user2->login($credentials4);
    
    //Userclass($db);// don't use like that,it will give you ERROR(it's private like singleton pattern says)
    
    推荐文章