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 函数),函数名也可能存在。

参见

添加说明

用户贡献说明 23 说明

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

例如,Wordpress 使用它来使函数“可插拔”。如果插件已经定义了一个可插拔函数,那么 WP 代码就知道不要尝试重新定义它。

但是,除非您将后面的任何函数定义包装在条件子句中,例如 if(){...}, 否则 function_exists() 将始终返回 true。这是 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
致命错误:调用未定义函数 qux()

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

<?php

namespace test;

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

function
example()
{

}

}

?>
7
chris at candm dot org dot uk
3 年前
这里一些提交中表达的困惑源于在条件块之外声明的函数在加载代码时被定义,因此无论在代码中的何处声明,它们都是可调用的且存在的,而那些在条件块内部声明的函数则只有在该块被执行时才被定义。因此

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

产生:“我是 foo”

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

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

产生:致命错误:未捕获错误:调用未定义函数 foo()
9
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
if(!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; }
?>

然后在您的包含文件中检查该函数是否存在。

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

简单但有效。
3
BruceB
8 年前
这不会像您期望的那样工作(即使您使用了 require/include_once)。

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

function
my_function()
{
// Do the work here
}
?>

但是,这样做是可行的。

<?php
if( ! function_exists('my_function'))
{
function
my_function()
{
// Do the work here
}
}
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'); // return Arrey
echo $if_is_disabled["m"]; // return text value
echo '<br/>';
echo
$if_is_disabled["s"]; // return 1 or 0
?>
0
webmaster at mamo-net dot de
16 年前
如果您在 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
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
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>";
}
?>

/*O U T P U T
A exist
B exist
C doesn't exist
D doesn't exist
*/
-2
dshearin at excite dot com
21 年前
这可以用于有条件地定义用户函数。从这个意义上说,它可以作为一种内联 include_once()。

例如,假设你有一个函数 A 调用函数 B。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
White-Gandalf
16 年前
我遇到了与“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 秒。
-5
chaumo
19 年前
为了避免直接调用,这可能比 function_exists 更好
在父文件中
<?php
define
("IN_MODULE",true);
?>
以及在目标文件中
<?php
if(!defined("IN_MODULE")) die("Can't access the file directly");
?>
-6
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 语句都没有执行。
-7
zach at bygeekz dot com
15 年前
致:php at fluidthoughts dot com

你没有与 false 进行比较,而是与 true 进行比较,所以它会返回 true,因为 false != true
true 等于 1、True、(bool)True 等等。
false 等于 0、False、Null 等等
<?php

$foo
=null;
if (
$foo) { echo 'yay'; } //不会输出 yay,因为 null 不等于 True

$foo=false;
if (
$foo) { echo 'yay'; } //不会输出 yay,因为 false 不等于 True

$foo=null;
if (!
$foo) { echo 'yay'; } //输出 yay!

$foo=false;
if (!
$foo) { echo 'yay'; } //输出 yay!

?>

这...
<?php
if (!function_exists('')) {
echo
"empty string function doesnt exist as compared as negative\n";
}

if (!
function_exists(NULL)) {
echo
"NULL function doesnt exist as compared as negative\n";
}
?>
有效。

或者,进入存在...

使用你的代码。 由于它们不存在,所以不会进入..
-6
eddiec at stararcher dot com
17 年前
请注意,在以下情况下, function_exists 将返回 TRUE,可能是因为函数“testfunc”在脚本解析/解释时定义,在运行时调用 function_exists 之前。

<?php
if (function_exists('testfunc')) return;
function
testfunc() { }
?>

因此,这种构造对于防止 testfunc 在脚本被多次包含或引用时被多次定义是无效的。

然而,以下构造可以防止 testfunc 被多次定义

<?php
if (!function_exists('testfunc')) {
function
testfunc() { }
}
?>

将此与定义()的类似用法进行对比,定义()完全是在运行时评估的。 这些都有效

<?php
if (defined('testfunc_defined')) return;
define('testfunc_defined', 1);
function
testfunc() { }
?>

以及...

<?php
if (!defined('testfunc_defined')) {
define('testfunc_defined', 1);
function
testfunc() { }
}
-14
dieter at edarta dot be
17 年前
致 brooklynphil at hotmail dot com

您的帖子具有误导性,特别是您描述的第三个和最后一个速度测试是不公平的比较。

<?php
is_callable
('test','test');
?>

第二个参数 $syntax_only 的值为“test”,这将被评估为布尔值 true。 换句话说,这与像这样调用函数完全一样

<?php
is_callable
('test',true);
?>

当然,这会更快,因为 is_callable 只进行非常基本的语法检查。 从文档中:'它只会拒绝不是字符串的简单变量,或者结构不符合作为回调使用的数组。'

如果您省略这个错误的第三个测试,那么根据您的示例,function_exists 的速度要快 2 到 4 倍。

我希望你明白,循环测试函数并不那么简单。:)

rtfm
To Top