上周我了解到,通过编写__autoload()
函数可以将类包含在项目中。然后我了解到使用自动加载器不仅是一种技术,也是一种模式。
现在我在我的项目中使用自动加载器,我发现它非常有用。我想知道是否可以用功能做同样的事情。忘记在其中包含正确的PHP文件可能非常有用。
那么,是否可以创建一个功能自动加载器?
答案 0 :(得分:57)
功能没有自动加载功能。你有四个现实的解决方案:
将所有函数包装到命名空间类中(适合上下文)。所以假设你有一个名为string_get_letters
的函数。您可以将其添加到名为StringFunctions
的类作为静态函数。因此,您不必致电string_get_letters()
,而是致电StringFunctions::get_letters()
。然后,您将__autoload
这些命名空间类。
预加载所有功能。由于您正在使用类,因此您不应该 许多函数,因此只需预先加载它们。
使用前加载功能。在每个文件中,require_once
将在该文件中使用的函数文件。
首先不要使用功能。如果你正在开发OOP代码(无论如何你似乎都是这样),根本不需要函数。你需要一个函数(或多个)的所有东西,你可以以OO方式构建并避免使用函数。
就个人而言,我建议使用1,2或4,具体取决于您的确切需求以及代码库的质量和大小......
答案 1 :(得分:32)
如果您在项目中使用Composer,则可以将 files 指令添加到自动加载部分。
这实际上会在自动加载器中生成一个require_once,但感觉就像是真正的自动加载,因为你不需要处理它。
虽然它不是懒惰的装载。
取自Assetic:
的示例"autoload": {
"psr-0": { "Assetic": "src/" },
"files": [ "src/functions.php" ]
}
答案 2 :(得分:15)
我读了一段关于一个丑陋的黑客,它发现了致命的错误并试图包含并执行缺失的函数,但我肯定不会走那条路。
你最接近的是__call()
magic method,它对于方法而不是函数来说是__autoload()
。它可能足以满足您的需求;如果你有能力打电话给一个班级,并分别要求每个不同的功能。从PHP 5.3.0开始,您还有__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);
这将调用./path/to/functions/functionToLoad.php中定义的functionToLoad()
函数。
答案 3 :(得分:7)
好吧,像往常一样,有一个PECL扩展:
(来自:http://phk.tekwire.net/joomla/support/doc/automap.htm)
它应该自动加载函数以及类。然而,这对当前的PHP解释器不起作用。
(替代选项btw,是生成加载和运行命名空间对应项的存根函数。)
话虽如此。自动加载并不是普遍认为的好习惯。它导致阶级等级和对象幸福感过度分裂。 PHP自动加载的真正原因是因为包含和依赖管理系统还不成熟。
答案 4 :(得分:2)
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);
}
}
使用命名空间,我们可以:Fn::myFunc()
和spl_autoload_register()
。我在以下代码中使用了此代码:https://goo.gl/8dMIMj
答案 5 :(得分:1)
带有自动加载功能的新函数\ 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(); } } }
答案 6 :(得分:1)
我使用一个类和__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',
],
]
];
}
}
然后我可以像调用函数一样:
$config = API\Config\Slim;
$app = Slim\App($config())
答案 7 :(得分:0)
这是另一个相当复杂的例子,基于本讨论中的建议。 代码也可以在这里看到: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);
}
}
答案 8 :(得分:0)
虽然您无法自动加载函数和常量,但您可以使用类似jesseschalken/autoload-generator的内容,它会自动检测哪些文件包含无法自动加载的内容并急切加载它们。
答案 9 :(得分:0)
将所有函数文件包含在一个文件中,然后包含它
//文件1
的 db_fct.php 强>
//文件2
的 util_fct.php 强>
//在 functions.php 中包含所有其他文件
driver.findElement(By.cssSelector("div[style='left:252px;width:117px;height:24px;']"));
无论何时需要功能,都要包含 functions.php 。
答案 10 :(得分:-3)
试试这个
if ($handle = opendir('functions')) {
while (false !== ($entry = readdir($handle))) {
if (strpos($entry, '.php') !== false) {
include("functions/$entry");
}
}
closedir($handle);
}