php 功能自动加载器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4737199/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Autoloader for functions
提问by Shoe
Last week I learned that classes can be included in your project by writing an __autoload()
function. Then I learned that using an autoloader isn't only a technique but also a pattern.
上周我了解到可以通过编写__autoload()
函数将类包含在您的项目中。然后我了解到使用自动加载器不仅是一种技术,也是一种模式。
Now I'm using the autoloader in my project and I've found it very very useful. I was wondering if it could be possible to do the same thing with functions. It could be very useful to forget about including the right PHP file with functions inside it.
现在我在我的项目中使用自动加载器,我发现它非常有用。我想知道是否可以用函数做同样的事情。忘记在其中包含包含函数的正确 PHP 文件可能非常有用。
So, is it possible to create a function autoloader?
那么,是否可以创建一个函数自动加载器?
回答by ircmaxell
There is no function auto-loader for functions. You have four realistic solutions:
函数没有函数自动加载器。你有四个现实的解决方案:
Wrap all functions into namespacing classes (context appropriate). So let's say you have a function called
string_get_letters
. You could add that to a class calledStringFunctions
as a static function. So instead of callingstring_get_letters()
, you'd callStringFunctions::get_letters()
. You would then__autoload
those namespaced classes.Pre-load all functions. Since you're using classes, you shouldn't have thatmany functions, so just pre-load them.
Load functions prior to using them. In each file,
require_once
the function files that are going to be used in that file.Don't use functions in the first place. If you are developing OOP code (which it seems like you are anyway), there should be little to no need for functions at all. Everything you would need a function (or multiple) for, you could build in a OO manner and avoid the need for functions.
将所有函数包装到命名空间类中(适合上下文)。因此,假设您有一个名为
string_get_letters
. 您可以将其添加到称为StringFunctions
静态函数的类中。因此string_get_letters()
,您不必调用,而是调用StringFunctions::get_letters()
。然后,您将使用__autoload
那些命名空间类。预加载所有功能。由于您使用的是类,因此您不应该拥有那么多函数,因此只需预加载它们即可。
在使用它们之前加载函数。在每个文件中,
require_once
将在该文件中使用的函数文件。首先不要使用函数。如果您正在开发 OOP 代码(无论如何您似乎都是这样),那么应该几乎不需要函数。您需要一个(或多个)函数的所有内容,您都可以以面向对象的方式构建并避免对函数的需求。
Personally, I'd suggest either 1, 2 or 4 depending on your exact need and the quality and size of your codebase...
就个人而言,我建议使用 1、2 或 4,具体取决于您的确切需求以及代码库的质量和大小...
回答by ivoba
If you are using Composer in your Project, you can add a filesdirective to the autoload section.
如果您在项目中使用 Composer,则可以向自动加载部分添加文件指令。
This will than actually generate a require_once in the autoloader, but it feels like real autoloading, because you dont have to take care of that.
Its not lazy loading though.
这实际上会在自动加载器中生成一个 require_once ,但感觉就像真正的自动加载,因为您不必处理它。
虽然它不是延迟加载。
Example taken from Assetic:
来自Assetic 的示例:
"autoload": {
"psr-0": { "Assetic": "src/" },
"files": [ "src/functions.php" ]
}
回答by Alix Axel
I read something a while back about an ugly hack that caught fatal errors and tried to include and execute the missing function(s), but I definitely wouldn't go that road.
不久前,我读到了一些关于捕获致命错误的丑陋 hack 的内容,并试图包含和执行丢失的函数,但我绝对不会走那条路。
The closest thing you have is the __call()
magic method, which is sort of a __autoload()
for methods, not functions. It might be good enough for your needs; if you can afford to call a class and require each different function separately. Since PHP 5.3.0, you also have __callStatic()
.
您拥有的最接近的东西是__call()
magic method,它是一种__autoload()
for 方法,而不是函数。它可能足以满足您的需求;如果您有能力调用一个类并分别需要每个不同的函数。自 PHP 5.3.0 起,您还拥有__callStatic()
.
An example using __callStatic()
:
使用示例__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);
This would call the functionToLoad()
function defined in ./path/to/functions/functionToLoad.php.
这将调用functionToLoad()
./path/to/functions/functionToLoad.php 中定义的函数。
回答by mario
Well, as usual there is a PECL extension for that:
好吧,像往常一样,有一个 PECL 扩展:
(via: http://phk.tekwire.net/joomla/support/doc/automap.htm)
(通过:http: //phk.tekwire.net/joomla/support/doc/automap.htm)
It's supposed to autoload functions as well as classes. Which however doesn't work with the current PHP interpreter yet.
它应该自动加载函数和类。然而,它不适用于当前的 PHP 解释器。
(An alternative option btw, is generating stub functions that load and run namespaced counterparts.)
(顺便说一句,另一个选项是生成加载和运行命名空间对应项的存根函数。)
That being said. Autoloading is not universally considered a good practice. It leads to overly fractured class hierarchies and object happiness. And the real reason PHP has autoloading is because include and dependency management systems are inmature.
话虽如此。自动加载并不普遍被认为是一种好的做法。它会导致过度分裂的阶级等级和对象幸福感。PHP 具有自动加载功能的真正原因是包含和依赖管理系统不成熟。
回答by Bryan Horna
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);
}
}
And using namespaces, we can do: Fn::myFunc()
and spl_autoload_register()
. I've used this code with examples at: https://goo.gl/8dMIMj
使用命名空间,我们可以做到:Fn::myFunc()
和spl_autoload_register()
。我已将此代码与示例一起使用:https: //goo.gl/8dMIMj
回答by Ares
new Functions\Debug() will load functions to root namespace.
new Functions\Debug() 将函数加载到根命名空间。
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(); } } }
回答by BugHunterUK
I use a Class and __invoke. The __invoke
method is called when a script calls a class as a function. I often do something like this:
我使用 Class 和__invoke。__invoke
当脚本将类作为函数调用时,将调用该方法。我经常做这样的事情:
<?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',
],
]
];
}
}
I can then call like a function:
然后我可以像函数一样调用:
$config = API\Config\Slim;
$app = Slim\App($config())
回答by dashohoxha
Here is another rather complex example, based on the suggestions in this discussion. The code can also be seen here: lib/btr.php
这是另一个相当复杂的例子,基于本次讨论中的建议。代码也可以在这里看到: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: http://stackoverflow.com/questions/4737199/autoloader-for-functions
*/
class btr {
/**
* Make it TRUE to output debug info on '/tmp/btr.log'.
*/
const DEBUG = FALSE;
/**
* The namespace of the functions.
*/
const NS = 'BTranslator';
/**
* Relative directory where the functions are located.
*/
const FN = 'fn';
private function __construct() {}
private function __wakeup() {}
private function __clone() {}
/**
* Return the full name (with namespace) of the function to be called.
*/
protected static function function_name($function) {
return self::NS . '\' . $function;
}
/**
* Return the full path of the file to be loaded (with require_once).
*/
protected static function file($fname) {
return dirname(__FILE__) . '/' . self::FN . '/' . $fname . '.php';
}
/**
* If a function does not exist, try to load it from the proper file.
*/
public static function __callStatic($function, $args) {
$btr_function = self::function_name($function);
if (!function_exists($btr_function)) {
// Try to load the file that contains the function.
if (!self::load_search_dirs($function) or !function_exists($btr_function)) {
$dir = dirname(self::file($fname));
$dir = str_replace(DRUPAL_ROOT, '', $dir);
throw new Exception("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);
}
}
回答by Jesse
While you can't autoload functions and constants, you can use something like jesseschalken/autoload-generatorwhich will automatically detect what files contain things which can't be autoloaded and load them eagerly.
虽然您不能自动加载函数和常量,但您可以使用jesseschalken/autoload-generator 之类的东西,它会自动检测哪些文件包含无法自动加载的内容并急切地加载它们。
回答by Az.Youness
Include all functions file in one file and then include it
将所有函数文件包含在一个文件中,然后将其包含
//File 1
db_fct.php
//文件1
db_fct.php
//File 2
util_fct.php
//文件2
util_fct.php
//In a functions.phpinclude all other files
//在functions.php中包含所有其他文件
<?php
require_once 'db_fct.php';
require_once 'util_fct.php';
?>
Include functions.phpwhenever you need functions ..
包括的functions.php只要你需要的功能..