Autochargeur de fonctions

la semaine dernière, j'ai appris que les cours peuvent être inclus dans votre projet en écrivant une fonction __autoload() . Puis j'ai appris que l'utilisation d'un autoloader n'est pas seulement une technique mais aussi un modèle.

maintenant j'utilise l'autoloader dans mon projet et je l'ai trouvé très très utile. Je me demandais si il serait possible de faire la même chose avec les fonctions. Il pourrait être très utile d'oublier d'inclure le bon fichier PHP avec des fonctions à l'intérieur.

alors, est-il possible de créer une fonction autoloader?

46
demandé sur Shoe 2011-01-19 18:36:00

11 réponses

il n'y a pas de fonction Auto-loader pour les fonctions. Vous avez quatre solutions réalistes:

  1. Envelopper toutes les fonctions dans namespacing classes (dans un contexte approprié). Disons que vous avez une fonction appelée string_get_letters . Vous pouvez ajouter cela à une classe appelée StringFunctions comme une fonction statique. Donc au lieu d'appeler string_get_letters() , vous appelleriez StringFunctions::get_letters() . Vous voulez alors __autoload ces classes avec un nom.

  2. précharger toutes les fonctions. Puisque vous utilisez des classes, vous ne devriez pas avoir que beaucoup de fonctions, donc juste Pré-les charger.

  3. fonctions de Charge avant leur utilisation. Dans chaque fichier, require_once la fonction des fichiers qui vont être utilisés dans ce fichier.

  4. N'utilisez pas de fonctions en premier lieu. Si vous développez du code OOP (ce qui semble vous sont de toute façon), il devrait y avoir peu ou pas besoin de fonctions du tout. Tout ce que vous auriez besoin d'une fonction (ou multiple) pour, vous pourriez construire D'une manière OO et éviter le besoin de fonctions.

personnellement, je suggère soit 1, 2 ou 4 selon votre besoin exact et la qualité et la taille de votre base de code...

53
répondu ircmaxell 2013-01-01 03:02:20

si vous utilisez Composer dans votre projet, vous pouvez ajouter une directive files à la section autoload.

cela va générer une require_once dans l'autoloader, mais cela ressemble à un vrai autoloading, parce que vous n'avez pas à vous en occuper.

Ses pas le chargement paresseux.

exemple tiré de Assetic :

"autoload": {
        "psr-0": { "Assetic": "src/" },
        "files": [ "src/functions.php" ]
    }
29
répondu ivoba 2013-07-29 13:31:33

j'ai lu quelque chose il y a quelque temps au sujet d'un hack laid qui a attrapé des erreurs fatales et a essayé d'inclure et d'exécuter la fonction manquante(s), mais je ne voudrais certainement pas prendre cette route.

la chose la plus proche que vous avez est le __call() méthode magique , qui est une sorte de __autoload() pour les méthodes, pas les fonctions. Il pourrait être assez bon pour vos besoins; si vous pouvez vous permettre d'appeler une classe et demander à chaque fonction séparément. Depuis PHP 5.3.0, vous avez aussi __callStatic() .

exemple utilisant __callStatic() :

class Test
{
    public function __callStatic($m, $args)
    {
        if (function_exists($m) !== true)
        {
            if (is_file('./path/to/functions/' . $m . '.php') !== true)
            {
                return false;
            }

            require('./path/to/functions/' . $m . '.php');
        }

        return call_user_func_array($m, $args);
    }
}

Test::functionToLoad(1, 2, 3);

cela appellerait la fonction functionToLoad() définie dans ./chemin/vers/fonctions/functionToLoad.php.

14
répondu Alix Axel 2011-01-19 16:23:47

Eh bien, comme d'habitude il y a une extension PECL pour cela:

(via: http://phk.tekwire.net/joomla/support/doc/automap.htm )

il est censé autoload fonctions ainsi que les classes. Qui cependant ne fonctionne pas encore avec L'interpréteur PHP actuel.

(Une option alternative, btw, est de générer des fonctions de BUB qui chargent et exécutent des contreparties namespaced.)

cela dit. Chargement automatique n'est pas universellement considérée comme une bonne pratique. Cela conduit à des hiérarchies de classe trop fracturées et au bonheur de l'objet. Et la vraie raison pour laquelle PHP a l'autoloading est parce que les systèmes de gestion des inclusions et des dépendances sont en nature.

7
répondu mario 2013-03-09 06:51:12
namespace MyNamespace;

class Fn {

    private function __construct() {}
    private function __wakeup() {}
    private function __clone() {}

    public static function __callStatic($fn, $args) {
        if (!function_exists($fn)) {
            $fn = "YOUR_FUNCTIONS_NAMESPACE\$fn";
            require str_replace('\', '/', $fn) . '.php';
        }
        return call_user_func_array($fn, $args);
    }

}

et en utilisant des espaces de noms, nous pouvons faire: Fn::myFunc() et spl_autoload_register() . J'ai utilisé ce code avec des exemples à: https://goo.gl/8dMIMj

2
répondu bryanjhv 2015-08-12 23:01:36

voici un autre exemple assez complexe, basé sur les suggestions de cette discussion. Le code peut également être consulté ici: lib / btr.php

<?php
/**
 * A class that is used to autoload library functions.
 *
 * If the function btr::some_function_name() is called, this class
 * will convert it into a call to the function
 * 'BTranslator\some_function_name()'. If such a function is not
 * declared then it will try to load these files (in this order):
 *   - fn/some_function_name.php
 *   - fn/some_function.php
 *   - fn/some.php
 *   - fn/some/function_name.php
 *   - fn/some/function.php
 *   - fn/some/function/name.php
 * The first file that is found will be loaded (with require_once()).
 *
 * For the big functions it makes more sense to declare each one of them in a
 * separate file, and for the small functions it makes more sense to declare
 * several of them in the same file (which is named as the common prefix of
 * these files). If there is a big number of functions, it can be more
 * suitable to organize them in subdirectories.
 *
 * See: /q/autoloader-for-functions-9970/"Function $btr_function could not be found on $dir");
      }
    }
    return call_user_func_array($btr_function, $args);
  }

  /**
   * Try to load files from subdirectories
   * (by replacing '_' with '/' in the function name).
   */
  protected static function load_search_dirs($fname) {
    do {
      self::debug($fname);
      if (file_exists(self::file($fname))) {
        require_once(self::file($fname));
        return TRUE;
      }
      if (self::load_search_files($fname)) {
        return TRUE;
      }
      $fname1 = $fname;
      $fname = preg_replace('#_#', '/', $fname, 1);
    } while ($fname != $fname1);

    return FALSE;
  }

  /**
   * Try to load files from different file names
   * (by removing the part after the last undescore in the functin name).
   */
  protected static function load_search_files($fname) {
    $fname1 = $fname;
    $fname = preg_replace('/_[^_]*$/', '', $fname);
    while ($fname != $fname1) {
      self::debug($fname);
      if (file_exists(self::file($fname))) {
        require_once(self::file($fname));
        return TRUE;
      }
      $fname1 = $fname;
      $fname = preg_replace('/_[^_]*$/', '', $fname);
    }

    return FALSE;
  }

  /**
   * Debug the order in which the files are tried to be loaded.
   */
  public static function debug($fname) {
    if (!self::DEBUG) {
      return;
    }
    $file = self::file($fname);
    $file = str_replace(DRUPAL_ROOT, '', $file);
    self::log($file, 'Autoload');
  }

  /**
   * Output the given parameter to a log file (useful for debugging).
   */
  public static function log($var, $comment ='') {
    $file = '/tmp/btr.log';
    $content = "\n==> $comment: " . print_r($var, true);
    file_put_contents($file, $content, FILE_APPEND);
  }
}
0
répondu dashohoxha 2014-09-02 20:13:27

bien que vous ne pouvez pas autoload fonctions et constantes, vous pouvez utiliser quelque chose comme jesseschalken/autoload-generator qui détectera automatiquement quels fichiers contiennent des choses qui ne peuvent pas être autoloadées et les charger avec empressement.

0
répondu Jesse 2015-07-29 12:37:05

Inclure toutes les fonctions de fichier dans un fichier et de l'inclure

/ / File 1

db_fct.php

/ / File 2

util_fct.php

//dans une fonction .php comprennent tous les autres fichiers

<?php

require_once 'db_fct.php';
require_once 'util_fct.php';
?>

Inclure des fonctions.php chaque fois que vous avez besoin de fonctions ..

0
répondu BBeta 2016-10-21 09:25:45

nouvelles fonctions\Debug () avec autoload chargera des fonctions dans l'espace de noms racine.

namespace Functions
{

    class Debug
    {
    }
}
namespace
{

    if (! function_exists('printr')) {

        /**
         *
         * @param mixed $expression
         */
        function printr()
        {
            foreach (func_get_args() as $v) {
                if (is_scalar($v)) {
                    echo $v . "\n";
                } else {
                    print_r($v);
                }
            }
            exit();
        }
    }
}
0
répondu Ares 2017-11-28 13:08:44

j'utilise une Classe et __invoquer . Le __invoke la méthode est appelée lorsqu'un script appelle une classe comme une fonction. Je fais souvent quelque chose comme ça:

<?php

namespace API\Config;

class Slim {
  function __invoke() {
    return [
      'settings' => [
        'displayErrorDetails' => true,
        'logger' => [
          'name' => 'api',
          'level' => Monolog\Logger\Logger::DEBUG,
          'path' => __DIR__ . '/../../logs/api.log',
        ],
      ]
    ];
  }
}

je peux alors appeler comme une fonction:

$config = API\Config\Slim;
$app = Slim\App($config())
0
répondu BugHunterUK 2018-09-24 22:45:35

essayez cette

if ($handle = opendir('functions')) {
    while (false !== ($entry = readdir($handle))) {
        if (strpos($entry, '.php') !== false) {
            include("functions/$entry");
        }
    }
    closedir($handle);
}
-3
répondu HeroWaar 2015-05-20 19:26:29