PHP call_user_func เทียบกับฟังก์ชันการโทร


92

ฉันแน่ใจว่ามีคำอธิบายที่ง่ายมากสำหรับเรื่องนี้ อะไรคือความแตกต่างระหว่างสิ่งนี้:

function barber($type){
    echo "You wanted a $type haircut, no problem\n";
}
call_user_func('barber', "mushroom");
call_user_func('barber', "shave");

... และสิ่งนี้ (และประโยชน์คืออะไร?):

function barber($type){
    echo "You wanted a $type haircut, no problem\n";
}
barber('mushroom');
barber('shave');

คำตอบ:


88

ใช้ชื่อฟังก์ชันจริงทุกครั้งเมื่อคุณทราบ

call_user_func มีไว้สำหรับเรียกฟังก์ชันที่คุณไม่รู้จักล่วงหน้า แต่มีประสิทธิภาพน้อยกว่ามากเนื่องจากโปรแกรมต้องค้นหาฟังก์ชันขณะรันไทม์


44
call_user_funcไม่จำเป็นต้องใช้ $some_func()คุณสามารถเรียกใช้ฟังก์ชันโดยใช้ฟังก์ชั่นตัวแปร: call_user_func_arrayเป็นสิ่งที่มีประโยชน์จริงๆ
Ionuț G. Stan

23
php ต้องการ "เพื่อค้นหาฟังก์ชันขณะรันไทม์เสมอ"
VolkerK

2
@Pacerier ไม่ถูกต้อง. $func = function(){};ฟังก์ชั่นที่ไม่ระบุชื่อยังคงอยู่ในตัวแปรคือ พารามิเตอร์ที่เป็นไปได้ใด ๆ สำหรับ call_user_func จะต้องสามารถเรียกใช้ได้ซึ่งหมายความว่ามีข้อมูลเพียงพอที่จะเข้าถึงโดยตรงไม่ว่าจะเป็น$func()หรือ$obj->{$func}()หรืออะไรก็ตาม
Benubird

2
"ประสิทธิภาพน้อยกว่า" นั้นน้อยมากโดยเฉพาะอย่างยิ่งตั้งแต่ php7 การโทรประมาณ ms / ล้านครั้ง: github.com/fab2s/call_user_func
fab2s

1
ตามแหล่งที่มาหนึ่ง"การเรียกใช้ฟังก์ชันที่ไม่มีอยู่ผ่านตัวแปรทำให้เกิดข้อผิดพลาดร้ายแรงในขณะที่ call_user_func () ส่งคืนคำเตือน" นั่นคือความแตกต่างอย่างหนึ่ง
mbomb007

32

แม้ว่าคุณสามารถเรียกชื่อฟังก์ชันตัวแปรด้วยวิธีนี้:

function printIt($str) { print($str); }

$funcname = 'printIt';
$funcname('Hello world!');

มีหลายกรณีที่คุณไม่รู้ว่าคุณผ่านข้อโต้แย้งไปกี่ข้อ พิจารณาสิ่งต่อไปนี้:

function someFunc() {
  $args = func_get_args();
  // do something
}

call_user_func_array('someFunc',array('one','two','three'));

นอกจากนี้ยังสะดวกสำหรับการเรียกวิธีการคงที่และวัตถุตามลำดับ:

call_user_func(array('someClass','someFunc'),$arg);
call_user_func(array($myObj,'someFunc'),$arg);

8
ฉันรู้ว่านี่เก่าแล้ว แต่หาบทความจากที่อื่นไม่เจอ การใช้ call_user_func ('customFunction') เป็นประโยชน์มากกว่าหรือไม่ที่จะใช้แทน $ variableFunction () อะไรคือความแตกต่าง? ขอบคุณ!
David Hobs

14

มีcall_user_funcตัวเลือกให้คุณทำสิ่งต่างๆเช่น:

$dynamicFunctionName = "barber";

call_user_func($dynamicFunctionName, 'mushroom');

โดยที่dynamicFunctionNameสตริงอาจน่าตื่นเต้นและสร้างขึ้นในขณะรันไทม์ คุณไม่ควรใช้ call_user_func เว้นแต่คุณจะต้องใช้เพราะมันช้ากว่า


2
ดูเหมือนว่าคุณสามารถใช้ฟังก์ชันตัวแปรในสถานการณ์นี้ได้
Anthony Rutledge

5

ฉันคิดว่ามันมีประโยชน์สำหรับการเรียกใช้ฟังก์ชันที่คุณไม่ทราบชื่อล่วงหน้า ... สิ่งที่ชอบ:

switch($value):
{
  case 7:
  $func = 'run';
  break;
  default:
  $func = 'stop';
  break;
}

call_user_func($func, 'stuff');

6
ไม่ เรายังทำได้$func('stuff');
ankush981

1
ใช่ แต่ความแตกต่างคือการใช้ตัวแปรจะทำให้เกิดข้อผิดพลาด PHP Fatal เทียบกับคำเตือน PHP หากใช้ call_user_func
Robert Brisita

สิ่งนี้ไม่ได้ลบล้างค่าของฟังก์ชันตัวแปรcall_user_func()ในสถานการณ์นี้
Anthony Rutledge

5

ด้วย PHP 7 คุณสามารถใช้ไวยากรณ์ของฟังก์ชันตัวแปรที่ดีกว่าได้ทุกที่ ทำงานร่วมกับฟังก์ชันคงที่ / อินสแตนซ์และสามารถใช้อาร์เรย์ของพารามิเตอร์ ข้อมูลเพิ่มเติมที่https://trowski.com/2015/06/20/php-callable-paradox

$ret = $callable(...$params);

AFAICT นี่เป็นคำตอบเดียวที่ตอบคำถามได้จริงๆ
Mormegil

3

ไม่มีประโยชน์ที่จะเรียกใช้ฟังก์ชันแบบนั้นเพราะฉันคิดว่าส่วนใหญ่ใช้เพื่อเรียกฟังก์ชัน "ผู้ใช้" (เช่นปลั๊กอิน) เนื่องจากการแก้ไขไฟล์หลักไม่ใช่ตัวเลือกที่ดี นี่คือตัวอย่างสกปรกที่ Wordpress ใช้

<?php
/* 
* my_plugin.php
*/

function myLocation($content){
  return str_replace('@', 'world', $content);
}

function myName($content){
  return $content."Tasikmalaya";
}

add_filter('the_content', 'myLocation');
add_filter('the_content', 'myName');

?>

...

<?php
/*
* core.php
* read only
*/

$content = "hello @ my name is ";
$listFunc = array();

// store user function to array (in my_plugin.php)
function add_filter($fName, $funct)
{
  $listFunc[$fName]= $funct;
}

// execute list user defined function
function apply_filter($funct, $content)
{
  global $listFunc;

  if(isset($listFunc))
  {
    foreach($listFunc as $key => $value)
    {
      if($key == $funct)
      {
        $content = call_user_func($listFunc[$key], $content);
      }
    }
  }
  return $content;
}

function the_content()
{
  $content = apply_filter('the_content', $content);
  echo $content;
}

?>

....

<?php
require_once("core.php");
require_once("my_plugin.php");

the_content(); // hello world my name is Tasikmalaya
?>

เอาท์พุท

hello world my name is Tasikmalaya

0

ในตัวอย่างแรกของคุณคุณกำลังใช้ชื่อฟังก์ชันซึ่งเป็นสตริง มันอาจมาจากภายนอกหรือถูกกำหนดทันที นั่นคือคุณไม่รู้ว่าจะต้องเรียกใช้ฟังก์ชันใดในขณะที่ทำการสร้างโค้ด


-1

เมื่อใช้เนมสเปซ call_user_func () เป็นวิธีเดียวในการเรียกใช้ฟังก์ชันที่คุณไม่ทราบชื่อมาก่อนเช่น:

$function = '\Utilities\SearchTools::getCurrency';
call_user_func($function,'USA');

หากฟังก์ชันทั้งหมดของคุณอยู่ในเนมสเปซเดียวกันก็จะไม่เป็นปัญหาเช่นนี้เนื่องจากคุณสามารถใช้สิ่งนี้:

$function = 'getCurrency';
$function('USA');

แก้ไข: ตามที่ @Jannis บอกว่าฉันผิดฉันทำการทดสอบอีกเล็กน้อยและไม่มีโชคมากนัก:

<?php
namespace Foo {

    class Bar {
        public static function getBar() {
            return 'Bar';
        }
    }
    echo "<h1>Bar: ".\Foo\Bar::getBar()."</h1>";
    // outputs 'Bar: Bar'
    $function = '\Foo\Bar::getBar';
    echo "<h1>Bar: ".$function()."</h1>";
    // outputs 'Fatal error: Call to undefined function \Foo\Bar::getBar()'
    $function = '\Foo\Bar\getBar';
    echo "<h1>Bar: ".$function()."</h1>";
    // outputs 'Fatal error: Call to undefined function \foo\Bar\getBar()'
}

คุณสามารถดูผลลัพธ์ผลลัพธ์ได้ที่นี่: https://3v4l.org/iBERhดูเหมือนว่าวิธีที่สองจะใช้ได้กับ PHP 7 เป็นต้นไป แต่ไม่ใช่ PHP 5.6


1
. เพราะไม่เป็นความจริง $ fn = '\ Foo \ Bar \ getCurrency'; $ fn ();
ม.ค. Sverre

สวัสดี @Jannis ฉันไม่พบว่ามันเป็นความจริงบางทีคุณอาจเห็นว่าฉันผิดพลาดตรงไหนฉันได้เพิ่มตัวอย่างที่ละเอียดมากขึ้นในคำตอบของฉัน
ThomasRedstone

@ThomasRedstone คุณต้องการฟังก์ชั่นเหล่านั้นมาก่อนหรือไม่? php ไม่โหลดฟังก์ชั่นอัตโนมัติจากไฟล์อื่น นอกจากนี้ตัวอักษรขนาดเล็กหรือตัวใหญ่ในเนมสเปซ บาร์เป็นชั้นเรียนหรือไม่? นั่นคืออีกกรณีหนึ่ง
przemo_li

สวัสดี @przemo_li นี่เป็นไฟล์เดียว (ทั้งหมดอยู่ในเนมสเปซ) ไม่แน่ใจว่าเกิดอะไรขึ้นกับชื่อเนมสเปซในการป้องกันของฉันฉันเขียนคำตอบเมื่อ 4 ปีก่อนฉันอัปเดตเนมสเปซและเพิ่มในบันทึกเกี่ยวกับ PHP 7 พร้อมลิงก์เพื่อดูผลลัพธ์จริง ฉันยังไม่รู้ว่า jansverre ใช้งานได้อย่างไร PHP 7 ไม่เข้าสู่อัลฟาจนถึงวันที่ 11 มิ.ย. 2558
ThomasRedstone
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.