2009-04-08 6 views
2

Est-il possible en php de charger une fonction, par exemple d'un fichier externe à inclure dans une classe. Je suis en train de créer un chargeur pour les fonctions d'aide afin que je puisse appeler:Charger dynamiquement des fonctions dans une classe à partir d'un fichier externe

$registry->helper->load('external_helper_function_file'); 

après qu'il devrait pouvoir appeler la fonction dans le fichier comme ceci:

$registry->helper->function(); 

Merci pour toute aide

+0

$ registry est juste une classe pour stocker des fonctions et des variables pour un accès global. – saint

Répondre

7

Abstraction faite des avis qu'il il est bon design POO. C'est possible même avec la version actuelle de PHP, bien que pas aussi propre que cela puisse être avec PHP5.3.

class Helper { 
    /* ... */ 
    function load($file) { 
     include_once($file); 
    } 
    function __call($functionName, $args) { 
     if(function_exists($functionName)) 
     return call_user_func_array($functionName, $args); 
    } 

} 
+1

Vous pouvez utiliser call_user_func_array(), dans votre exemple la fonction serait passée tous les arguments dans un argument de tableau –

+0

@tomhaigh: right, corrigé. – vartec

+0

Cest exactement ce que je cherchais – saint

0

Donc, vous voulez non seulement include un fichier, mais include dans le champ d'un objet?

...

Je pense que vous allez sur ce dans le mauvais sens. Cela a plus de sens si l'objet registry a une série de membres auxiliaires, qui ont leurs propres fonctions. Le résultat net pourrait ressembler à ceci:

$registry->aHelper->aFunction(); 
$registry->aDifferentHelper->aDifferentFunction(); 

Avec une utilisation prudente de la syntaxe {}, vous devriez être en mesure d'ajouter dynamiquement des objets membres à votre objet dieu.

À ce stade, il vaut la peine de noter qu'un god object est presque invariable et anti-pattern. Si vous avez besoin de ces fonctions globalement, utilisez une technique d'inclusion bootstrap et placez-la dans la portée globale. Si vous avez besoin de transmettre ces données, passez-les aux fonctions requises ou stockez-les dans une base de données et récupérez-les ailleurs.

Je sais que l'objet de Dieu vraiment ressemble à une bonne idée, mais je vous promets que cela va rendre les choses un peu plus tard.

+0

Merci pour l'entrée. Ces fonctions auxiliaires peuvent augmenter invariablement. Donc, je les veux seulement chargés en cas de besoin. Ce serait génial si quelqu'un pouvait pointer dans la bonne direction. Quelque chose comme les helpers CI – saint

+0

Puis-je vous suggérer d'ouvrir la base de code CodeIgniter, alors? Si c'est votre modèle d'idée, alors cela semble être un bon point de départ. – Kalium

2

ok, d'abord, je suis d'accord que c'est de mauvaises manières. aussi, en 5.3, vous pourriez utiliser la nouvelle syntaxe de fermeture avec le mot magique __call pour utiliser les opérateurs en tant que fonctions (style JS). Maintenant, si nous voulons fournir un moyen de le faire de cette façon, je peux penser à utiliser create_fnuction, mélangé avec la magie __ call. En gros, vous utilisez un modèle regex pour convertir les fonctions en chaînes compatibles et les mettre dans un membre privé. que vous utilisez la méthode __call pour les récupérer. Je travaille sur une petite démo.

ok, voici la classe. Je suis inspiré d'une classe que j'ai vu il y a quelques semaines qui ont utilisé des fermetures pour mettre en œuvre des objets de style JS:

/** 
* supplies an interface with which you can load external functions into an existing object 
* 
* the functions supplied to this class will recive the classes referance as a first argument, and as 
* a second argument they will recive an array of supplied arguments. 
* 
* @author arieh glazer <[email protected]> 
* @license MIT like 
*/ 
class Function_Loader{ 
    /** 
    * @param array holder of genarated functions 
    * @access protected 
    */ 
    protected $_funcs = array(); 

    /** 
    * loads functions for an external file into the object 
    * 
    * a note- the file must not contain php tags. 
    * 
    * @param string $source a file's loaction 
    * 
    * @access public 
    */ 
    public function load($source){ 
     $ptrn = '/function[\s]+([a-zA-Z0-9_-]*)[\s]*\((.*)\)[\s]*{([\w\s\D]+)}[\s]*/iU'; 
     $source = file_get_contents($source); 
     preg_match_all($ptrn,$source,$matches); 
     $names = $matches[1]; 
     $vars = $matches[2]; 
     $funcs = $matches[3]; 
     for ($i=0,$l=count($names);$i<$l;$i++){ 
      $this->_funcs[$names[$i]] = create_function($vars[$i],$funcs[$i]); 
     } 
    } 

    public function __call($name,$args){ 
     if (isset($this->_funcs[$name])) $this->_funcs[$name]($this,$args); 
     else throw new Exception("No Such Method $name"); 
    } 
} 

1er limitations-, la source ne peut pas avoir des balises php. 2ème, les fonctions seront toujours publiques. 3ème- nous pouvons seulement imiter $ this. ce que j'ai fait était de passer comme un premier argument $ this, et le second est le tableau d'arguments (qui est une 4ème limite). De plus, vous ne pourrez pas accéder aux membres et aux méthodes non publiques à partir de la classe. un exemple pour un fichier source:

function a($self,$arr=array()){ 
    //assuming the object has a member called str 
    echo $self->str; 
} 

ce fut un exercice amusant pour moi, mais une mauvaise pratique dans l'ensemble

Questions connexes