PHP Conference Japan 2024

function_exists

(PHP 4, PHP 5, PHP 7, PHP 8)

function_exists如果已定义给定函数,则返回 true

描述

function_exists(string $function): bool

检查已定义函数列表,包括内置(内部)函数和用户定义函数,以查找 function

参数

function

函数名称,作为字符串。

返回值

如果 function 存在且为函数,则返回 true,否则返回 false

注意:

此函数将对构造(例如 include_onceecho)返回 false

示例

示例 #1 function_exists() 示例

<?php
if (function_exists('imap_open')) {
echo
"IMAP 函数可用。<br />\n";
} else {
echo
"IMAP 函数不可用。<br />\n";
}
?>

备注

注意:

即使由于配置或编译选项(例如 image 函数)导致函数本身无法使用,函数名称也可能存在。

参见

添加注释

用户贡献的注释 19 个注释

36
kitchin
12 年前
您可以使用此函数有条件地定义函数,请参阅:https://php.net/manual/en/functions.user-defined.php

例如,Wordpress 使用它来使函数“可插入”。如果插件已定义可插入函数,则 WP 代码知道不要尝试重新定义它。

但是 function_exists() 将始终返回 true,除非您将任何后续函数定义包装在条件子句中,例如 if(){...}。这是 PHP 解析中的一个微妙问题。一些例子

<?php
if (function_exists('foo')) {
print
"foo 已定义\\n";
} else {
print
"foo 未定义\\n";
}
function
foo() {}

if (
function_exists('bar')) {
print
"bar 已定义\\n";
} else {
print
"正在定义 bar\\n";
function
bar() {}
}
print
"调用 bar\\n";
bar(); // 可以调用之前有条件定义的函数

print "调用 baz\\n";
baz(); // 可以调用之后无条件定义的函数
function baz() {}

qux(); // 不能调用之后有条件定义的函数
if (!function_exists('qux')) {
function
qux() {}
}
?>
打印
foo 已定义
正在定义 bar
调用 bar
调用 baz
PHP 致命错误:调用未定义函数 qux()

任何异常可能都是由于包含/加载文件顺序导致的。
26
michael at squiloople dot com
9 年前
需要注意的是,function_exists 检查与根命名空间无关。这意味着应将命名空间附加到检查中

<?php

namespace test;

if (!
function_exists(__NAMESPACE__ . '\example'))
{

function
example()
{

}

}

?>
6
chris at candm dot org dot uk
3 年前
此处某些提交中表达的困惑源于以下事实:在条件块外部声明的函数在代码加载时定义,因此可以在代码中的任何位置调用和存在,而那些在条件块内部声明的函数直到该块执行时才定义。因此

echo foo();
function foo() { return "我是 foo"; }

产生:“我是 foo”

但是,由于那些在条件内部的函数在代码执行期间遇到时才定义

echo foo();
if(true) {
function foo() { return "我是 foo"; }
}

产生:致命错误:未捕获的错误:调用未定义函数 foo()
10
ayyappan dot ashok at gmail dot com
8 年前
PHP 基于某些条件支持嵌套函数。

请查看代码。

function Media(){ }

function Audio()
{
echo "插入 Audo 5.1:<br/>";
function Volume()
{
echo "音量控制:<br/>";
function Equalizer()
{
echo "均衡频段:<br/>";
}
}
}
// 调用嵌套函数
Audio();
Volume();
Equalizer();

if(function_exists('Volume'))
echo "TRUE";
else
echo "FALSE";
endif;

情况 1:// 结果:运行良好
--------
Audio();
Volume();
Equalizer();

情况 2:// 结果出现错误。必须先调用根函数 Audio。
--------
Volume();

情况 3:// 结果出现错误。必须先调用根函数 Volume。
--------
Audio();
Equalizer();

注意
应根据嵌套函数的使用顺序进行调用。
在我们的示例中,当未调用 Audio 并且立即尝试调用 Volume 时会出现错误。

即使 PHP 有可能使用嵌套函数,这样做似乎也显得复杂。最好在脚本逻辑上避免使用。

在 PHP 5.5.32 上测试
9
andi at splitbrain dot org
18 年前
function_exists 将对使用 disable_functions ini 指令禁用的函数返回 false。但是,这些函数仍然已声明,因此尝试自己定义它们将失败。

<?php
如果(!function_exists('readfile')){
function
readfile($file){
$handle=@fopen($cache,"r");
echo @
fread($handle,filesize($file));
@
fclose($handle);
}
}
?>

如果 readfile 函数被 disable_functions 禁用,以上代码将引发 "Cannot redeclare readfile()" 的致命错误。
4
fili at fili dot nl
19 年前
为了防止直接调用包含的文件,我使用以下技术。

在主文件中创建一个具有随机名称的空函数。例如

<?php
function hjudejdjiwe() { return true; }
?>

然后在你的 include 文件中检查此函数是否存在

<?php
if (!function_exists('hjudejdjiwe')) { die('!'); }
?>

简单但有效。
3
BruceB
9 年前
这可能不会像你预期的那样运行(即使你使用 require/include_once 进行了巧妙处理)。

<?php
if(function_exists('my_function'))
{
throw new
Exception("'my_function' is already defined!");
}

function
my_function()
{
// 在这里执行工作
}
?>

然而,这样做是有效的

<?php
if( ! function_exists('my_function'))
{
function
my_function()
{
// 在这里执行工作
}
}
else
{
throw new
Exception("'my_function' is already defined!");
}
?>

这是否与 PHP 的解析/执行阶段、全局/局部作用域、花括号或其他某些内容有关,我不知道,但后一种丑陋的方案有效,而前一种则宣称 "my_function" 已定义而崩溃。

希望这能为某些人节省几分钟的调试时间……
0
admin at gk-root dot com
12 年前
// 如果你想检查函数在 php.ini 中是启用还是禁用,可以使用此函数

<?php
function func_enabled($func) {
$disabled = explode(',', ini_get('disable_functions'));
foreach (
$disabled as $disableFunction) {
$is_disabled[] = trim($disableFunction);
}
if (
in_array($func,$is_disabled)) {
$it_is_disabled["m"] = $func.'() has been disabled for security reasons in php.ini';
$it_is_disabled["s"] = 0;
} else {
$it_is_disabled["m"] = $func.'() is allow to use';
$it_is_disabled["s"] = 1;
}
return
$it_is_disabled;
}
?>

// 如何使用示例

<?php
$if_is_disabled
= func_enabled('exec'); // 返回数组
echo $if_is_disabled["m"]; // 返回文本值
echo '<br/>';
echo
$if_is_disabled["s"]; // 返回 1 或 0
?>
0
webmaster at mamo-net dot de
17 年前
如果你在 php.ini 中使用 suhosin.executor.func.blacklist 而不是 disabled_functions,则 function_exists 将对禁用的函数返回 true。我使用它来使 suhosin.executor.func.blacklist 和 disabled_functions 的行为相同。

<?php
function suhosin_function_exists($func) {
if (
extension_loaded('suhosin')) {
$suhosin = @ini_get("suhosin.executor.func.blacklist");
if (empty(
$suhosin) == false) {
$suhosin = explode(',', $suhosin);
$suhosin = array_map('trim', $suhosin);
$suhosin = array_map('strtolower', $suhosin);
return (
function_exists($func) == true && array_search($func, $suhosin) === false);
}
}
return
function_exists($func);
}
?>
0
ckrack at i-z dot de
20 年前
我想知道在检查类方法时,is_callable 或 function_exists 哪个更快。

is_callable(array('foo', 'bar'));
function_exists('foo::bar');

使用一个简单的测试类,对每个操作进行 10000 次操作的结果如下:

is_callable:0.28671383857727 秒
function_exists:0.14569997787476 秒

(后续测试证明了这一点)。

因此,您可以看到,function_exists 的速度是 is_callable 的两倍。
-1
breadman
21 年前
函数内的函数最好使用 create_function() 的匿名返回值,除非你想在其他地方调用它。

但是,我在皮肤设计中使用过它:我使用 alert_box() 来显示某些错误,例如错误的 SQL 查询。这只是调用 display_alert(),它在我的皮肤脚本中定义。但是,有时在我知道要加载哪个皮肤之前就会调用 alert_box(),因此它有自己的功能,如果 function_exists('display_alert') 返回 false,它就会使用这些功能。
-1
Dan
18 年前
我想对以下帖子发表评论

注意:function_exists() 似乎是不区分大小写的(至少在 PHP 4.3.8 及更高版本中)。例如:

<?php
function MyCasedFunction() {
return
true;
}

// 将返回 true,即使大小写“错误”
if (function_exists("mYcAsEdFuNcTiOn"))
echo
"I see it!";
?>

我相信函数调用本身是不区分大小写的,因此此函数返回一个有效的真值。PHP 不关心大小写。
-2
neelam_ab2003 at yahoo dot co dot in
18 年前
<?php
/*PHP 不支持嵌套函数。我在 PHP_VERSION - 5.1.2 中尝试了以下操作*/

function A(){}

function
B(){
function
C(){
function
D(){}
}
}

IsFunctionExist('A');
IsFunctionExist('B');
IsFunctionExist('C');
IsFunctionExist('D');

function
IsFunctionExist($funcName){
echo
function_exists($funcName)?" $funcName exist <br>":" $funcName doesn't exist <br>";
}
?>

/*输出
A exist
B exist
C doesn't exist
D doesn't exist
*/
-3
bob at thethirdshift dot net
20 年前
我也想知道在检查类方法时,is_callable 或 function_exists 哪个更快。因此,我设置了以下测试

<?php
function doTimes($start, $end)
{
$start_time = explode (" ", $start);
$start_time = $start_time[1] + $start_time[0];
$end_time = explode (" ", $end);
$end_time = $end_time[1] + $end_time[0];
$time = $end_time - $start_time;
return
$time;
}

class
test
{
function
test()
{
return
true;
}
}

$callableIsTrue = false;
$startIsCallable = microtime();
for(
$i = 0; $i < 10000; $i++)
{
if(
is_callable(array('test', 'test'))) { $callableIsTrue = true; }
}
$endIsCallable = microtime();

$existsIsTrue = false;
$startExists = microtime();
for(
$i = 0; $i < 10000; $i++)
{
if(
function_exists('test::test')) { $existsIsTrue = true; }
}
$endExists = microtime();

$timeIsCallable = doTimes($startIsCallable, $endIsCallable);
$timeExists = doTimes($startExists, $endExists);

echo
"<b>is_callable = ".($callableIsTrue ? "TRUE" : "FALSE")."</b>, \n";
echo
"<b>function_exists = ".($existsIsTrue ? "TRUE" : "FALSE")."</b><br>\n";

echo
"<br>Did 10000 is_callables in ".$timeIsCallable." seconds";
echo
"<br>Did 10000 function_exists in ".$timeExists." seconds";
?>

这将输出

is_callable = TRUE, function_exists = FALSE

Did 10000 is_callables in 0.0640790462494 seconds
Did 10000 function_exists in 0.0304429531097 seconds

因此,function_exists 快两倍的事实,被它无法作用于类方法的事实(至少就我所知)所部分掩盖了。
-2
dshearin at excite dot com
21 年前
这可以用于有条件地定义用户函数。从这个意义上说,它可以充当一种内联的 include_once()。

例如,假设您有一个调用函数 B 的函数 A。B 仅在函数 A 内部使用,并且在脚本中的任何其他地方都不会被调用。将 B 定义在 A 的定义内部是合乎逻辑的(并且在 PHP 中完全合法),如下所示

<?php
function A($inputArray)
{
if (!
function_exists('B'))
{
function
B($item)
{
// 对 $item 执行某些操作
// 并返回结果
return $result;
}
}
foreach (
$inputArray as $nextItem) $outputArray[] = B($nextItem);
return
$outputArray;
}
?>

如果没有 function_exists 测试,您将在第二次调用 A 时收到一个致命错误,因为 PHP 会认为您正在尝试重新定义 B(在 PHP 中不合法)。测试的位置也很重要。由于 if 块是按顺序执行的,就像任何其他代码块一样,它必须出现在对其中定义的函数的任何调用之前。
-4
brooklynphil at hotmail dot com
17 年前
致 bob at thethirdshift dot net
关于 is_callable 与 function_exists。

使用您的代码
is_callable = TRUE, function_exists = FALSE

Did 10000 is_callables in 0.0443360805511 seconds
Did 10000 function_exists in 0.0111110210419 seconds

然后我们替换
is_callable(array('test','test'));

$callarray = array('test','test'); // 将此放在 for 循环之外
is_callable($callarray);

is_callable = TRUE, function_exists = FALSE

Did 10000 is_callables in 0.0314660072327 seconds
Did 10000 function_exists in 0.0120670795441 seconds

然后我们替换
is_callable(array('test','test'));

is_callable('test','test');

is_callable = TRUE, function_exists = FALSE

Did 10000 is_callables in 0.00991606712341 seconds
Did 10000 function_exists in 0.0113790035248 seconds

我希望您能看到循环测试函数并不那么简单。:)
-5
php at fluidthoughts dot com
16 年前
function_exists 在 NULL 和空字符串上返回 false

<?php
if (function_exists('')) {
echo
"empty string function exists\n";
}

if (
function_exists(NULL)) {
echo
"NULL function exists\n";
}
?>

当我运行这段代码时,这两个 echo 语句都没有执行。
-5
White-Gandalf
17 年前
我偶然发现了与“eddiec”相同的问题(用户无法或不愿使用“_once”后缀)。

对行为的另一种可能的解释

如果包含一个文件,它可能会在每次包含时都被解析。(?)
在解析过程中,会尝试注册全局作用域中的每个函数。当多次包含时,这会出错,并产生错误。

如果函数在块作用域内定义,则它们的注册似乎会延迟到执行该块时。因此,不是函数“function_exists”的功能错误,而是解释器的理念导致了这样的结果。

因此,可以通过简单地将 include_once 文件的内容放在块括号中来实现相同的效果

if (function_exists('function_in_question')) return;
{
function function_in_question(...)
{
...
}
...其他内容
}

...这等同于...

if (!function_exists('function_in_question'))
{
function function_in_question(...)
{
...
}
...其他内容
}
-4
b dot g dot dariush at gmail dot com
10 年前
function_exists() 在内部不会缓存其查询。

通过执行以下代码

$funcs = \array_shift(\get_defined_functions());
$l = new \core\utiles\loadTime;
$times = 0;
$l->start();
for($index = 0; $index<count($funcs); $index++)
{
foreach($funcs as $func)
{
$times++;
if(\function_exists($func)) ;
}
}
$s = $l->stop();
echo "<span style='color:green'>$times</span> took : $s";
# 输出将是
$> 2365444 took : 0.70324

通过执行

$funcs = \array_shift(\get_defined_functions());
$l = new \core\utiles\loadTime;
$times = 0;
$l->start();
static $func_check = array();
for($index = 0; $index<count($funcs); $index++)
{
foreach($funcs as $func)
{
$times++;
if(!isset($func_check[$func]))
{
if(\function_exists($func)) ;
$func_check[$func] = 1;
}
else $func_check[$func];
}
}
$s = $l->stop();
echo "<span style='color:green'>$times</span> took : $s";
# 输出将是
$> 2365444 took : 0.53446

当您使用静态数组缓存方法是否存在时,有 0.16878 秒的改进。
To Top