PHP Conference Japan 2024

function_exists

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

function_exists如果已定義給定函式,則回傳 true

說明

function_exists(字串 $function): 布林值

檢查已定義函式的清單,包括內建 (內部) 和使用者定義的函式,是否存在 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 則筆記

kitchin
12 年前
您可以使用這個函式來有條件地定義函式,請參閱:https://php.dev.org.tw/manual/en/functions.user-defined.php

例如,WordPress 使用它來使函式「可插拔」。如果一個外掛程式已經定義了一個可插拔函式,那麼 WP 程式碼就知道不要嘗試重新定義它。

但除非您將任何後續的函式定義包裝在條件子句中,例如 if(){...},否則 function_exists() 將始終回傳 true。這是 PHP 解析中的一個微妙之處。一些例子

<?php
if (function_exists('foo')) {
print
"foo defined\\n";
} else {
print
"foo not defined\\n";
}
function
foo() {}

if (
function_exists('bar')) {
print
"bar defined\\n";
} else {
print
"defining bar\\n";
function
bar() {}
}
print
"calling bar\\n";
bar(); // 可以呼叫前面有條件式定義的函式

print "calling baz\\n";
baz(); // 可以呼叫後面無條件式定義的函式
function baz() {}

qux(); // 不可以呼叫後面有條件式定義的函式
if (!function_exists('qux')) {
function
qux() {}
}
?>
印出
foo defined
defining bar
calling bar
calling baz
PHP 致命錯誤:呼叫未定義的函式 qux()

任何異常狀況可能都是因為引入/載入檔案的順序所造成。
michael at squiloople dot com
9 年前
需要注意的是,function_exists 檢查並非相對於根命名空間。這表示命名空間應該附加到檢查中

<?php

namespace test;

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

function
example()
{

}

}

?>
chris at candm dot org dot uk
3 年前
這裡某些提交內容中表達的困惑產生是因為在條件區塊外宣告的函式會在程式碼載入時定義,因此在程式碼中宣告它們的任何位置都可以呼叫和存在,而那些在條件區塊內宣告的函式則要到該區塊執行時才會定義。因此

echo foo();
function foo() { return "I am foo"; }

會產生:"I am foo"

然而,因為條件式內的函式是在程式碼執行期間遇到時才定義

echo foo();
if(true) {
function foo() { return "I am foo"; }
}

會產生:致命錯誤:未捕捉到的錯誤:呼叫未定義的函式 foo()
ayyappan dot ashok at gmail dot com
8 年前
PHP 基於特定條件支援巢狀函式。

請查看程式碼。

function Media(){ }

function Audio()
{
echo "已插入音訊 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 上測試
andi at splitbrain dot org
18 年前
對於使用 disable_functions ini 指令停用的函式,function_exists 將返回 false。然而,這些函式仍然被宣告,因此嘗試自行定義它們將會失敗。

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

如果 readfile 已被 disable_functions 禁用,以上程式碼將會產生「無法重新宣告 readfile()」的嚴重錯誤。
fili at fili dot nl
19 年前
為了防止直接呼叫被包含的檔案,我使用以下技巧。

在主檔案中建立一個具有隨機名稱的空函式。像這樣

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

然後在您的 include 檔案中檢查此函式是否存在

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

簡單但有效。
BruceB
9 年前
這並不會像您預期的那樣運作(即使您很聰明地使用 require/include_once)

<?php
if (function_exists('my_function'))
{
throw new
Exception("'my_function' 已被定義!");
}

function
my_function()
{
// 在這裡執行工作
}
?>

然而,這樣做是可行的

<?php
if ( ! function_exists('my_function'))
{
function
my_function()
{
// 在這裡執行工作
}
}
else
{
throw new
Exception("'my_function' 已被定義!");
}
?>

我不知道這是否與 PHP 的解析/執行階段或全域/區域範圍或那些大括號或其他東西有關,但後者這個醜陋的寫法有效,而前者則會炸掉,聲稱「my_function」已被定義。

希望這可以為某人節省幾分鐘的除錯時間...
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.'() 基於安全性考量,已在 php.ini 中被禁用';
$it_is_disabled["s"] = 0;
} else {
$it_is_disabled["m"] = $func.'() 可以使用';
$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
?>
webmaster at mamo-net dot de
17 年前
如果您在 php.ini 中使用 suhosin.executor.func.blacklist 而不是 disable_functions,即使函式被禁用,function_exists 仍會回傳 true。我使用這個方法來讓 suhosin.executor.func.blacklist 和 disable_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);
}
?>
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` 的兩倍。
breadman
21 年前
函式內的函式最好以 `create_function()` 的匿名返回值形式存在,除非您希望能夠在其他地方呼叫它。

然而,我在設計皮膚時使用了這個方法:我使用 `alert_box()` 來顯示某些錯誤,例如錯誤的 SQL 查詢。它只是呼叫 `display_alert()`,它在我的皮膚腳本中定義。但是,`alert_box()` 有時會在我知道要載入哪個皮膚之前被呼叫,所以如果 `function_exists('display_alert')` 返回 `false`,它就會使用自己的功能。
Dan
18 年前
我想對以下文章發表評論

注意事項:`function_exists()` 似乎不區分大小寫(至少在 PHP 4.3.8 中是這樣)。例如:

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

// 即使大小寫“錯誤”,也會返回 true
if (function_exists("mYcAsEdFuNcTiOn"))
echo
"I see it!";
?>

我相信函數呼叫本身是不區分大小寫的,所以這個函數返回一個有效的真值。PHP 不在乎大小寫。
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 存在 <br>":" $funcName 不存在 <br>";
}
?>

/*輸出結果
A 存在
B 存在
C 不存在
D 不存在
*/
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

執行 10000 次 is_callables 花費 0.0640790462494 秒
執行 10000 次 function_exists 花費 0.0304429531097 秒

因此,function_exists 速度快兩倍的事實,稍微被它不適用於類別方法的事實所掩蓋,至少就我所知是這樣。
dshearin at excite dot com
21 年前
這可以用來有條件地定義使用者函數。從這個意義上說,它可以充當一種內嵌的 include_once()。

例如,假設您有一個函數 A 呼叫函數 B。B 只在函數 A 內部使用,並且從未在腳本中的其他任何地方呼叫。在 A 的定義內部定義 B 是合乎邏輯的(在 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 區塊像任何其他程式碼區塊一樣按順序執行,因此它必須在對其中定義的函數的任何呼叫之前。
brooklynphil at hotmail dot com
17 年前
致 bob at thethirdshift dot net
關於 is_callable 與 function_exists。

使用您的程式碼
is_callable = TRUE, function_exists = FALSE

執行 10000 次 is_callables 花費 0.0443360805511 秒
執行 10000 次 function_exists 花費 0.0111110210419 秒

然後我們將
is_callable(array('test','test'));
替換為
$callarray = array('test','test'); // 將此程式碼放在 for 迴圈之外
is_callable($callarray);

is_callable = TRUE, function_exists = FALSE

執行 10000 次 is_callable 花費 0.0314660072327 秒
執行 10000 次 function_exists 花費 0.0120670795441 秒

然後我們將
is_callable(array('test','test'));
替換為
is_callable('test','test');

is_callable = TRUE, function_exists = FALSE

執行 10000 次 is_callable 花費 0.00991606712341 秒
執行 10000 次 function_exists 花費 0.0113790035248 秒

我希望你能看出,在迴圈中測試函式並非那麼簡單。 :)
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 陳述句都沒有執行。
White-Gandalf
17 年前
我遇到了與 "eddiec" 相同的問題(使用者無法或不願意使用 "_once" 後綴)。

針對此行為的另一種可能解釋

如果一個檔案被 include,它可能每次 include 時都會被解析。(?)
在解析過程中,會嘗試註冊全域範圍內的每個函式。如果多次 include 同一個檔案,這個過程就會出錯,並產生錯誤。

如果函式定義在區塊範圍內,它們的註冊似乎會延遲到該區塊執行時。因此,不是 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(...)
{
...
}
...其他程式碼
}
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