변수에 저장된 문자열에서 함수를 호출하는 방법은 무엇입니까?


289

함수를 호출 할 수 있어야하지만 함수 이름이 변수에 저장되어 있습니까? 예 :

함수 foo ()
{
  // 여기 코드
}

기능 표시 줄 ()
{
  // 여기 코드
}

$ functionName = "foo";
// $ functionName이 무엇인지에 따라 함수를 호출해야합니다.

답변:


465

85
이름이 변수에있는 객체의 함수를 호출해야하는 경우 다음과 같이하십시오 : call_user_func (array ($ obj, $ func), $ params)
BlackDivine

1
클래스와 메소드를 다루는 경우 아래의 답변을 참조하십시오. 내가 찾은 것을 기대하지 않았습니다.
Chris K

함수가 정의되지 않은 경우 함수 정의 오류를 어떻게 무효화 할 수 있습니까? if ($ functionName)이 충분합니까?
SaidbakR

14
@ sємsєм : is_callable기능을 사용해야합니다 . 변수가 함수 (함수의 이름, 객체 인스턴스와 함수 이름을 포함하는 배열 또는 익명의 함수 / 클로저)로 호출 될 수있는 것이 포함되어 있는지 확인합니다.
knittl

6
@Pacerier : 클래스 이름을 배열의 첫 번째 요소로 제공하십시오.call_user_func(array('ClassName', 'method'), $args)
knittl

122

내가 좋아하는 버전은 인라인 버전입니다.

${"variableName"} = 12;

$className->{"propertyName"};
$className->{"methodName"}();

StaticClass::${"propertyName"};
StaticClass::{"methodName"}();

대괄호 안에 변수 나 표현식도 넣을 수 있습니다!


1
@marcioAlmada : 이런 식으로 다른 사람의 답변을 편집하는 대신 의견을 게시하십시오. 혼란을 가중 시킵니다. [호기심을 가진 사람 : 설명에 대한 수정본 참조]
kryger

4
좋아요 @kryger. 2 행 {"functionName"}();은 합법적이지 않으며 구문 오류가 발생합니다.
marcio

4
답장을 보내 주셔서 감사합니다. 실제로 PHP 5.4에서도 오류가 발생하므로 구문은 객체 메소드에서만 작동합니다. 게시물을 수정했습니다.
Lajos Meszaros 2013


18

이미 언급했듯이 가장 안전한 방법을 사용 call_user_func()하거나 경로를 따라 내려갈 수 있는 몇 가지 방법이 있습니다 $function_name(). 이 두 가지 방법을 모두 사용하여 인수를 전달할 수 있습니다.

$function_name = 'foobar';

$function_name(arg1, arg2);

call_user_func_array($function_name, array(arg1, arg2));

호출하는 함수가 객체에 속하는 경우 여전히 다음 중 하나를 사용할 수 있습니다

$object->$function_name(arg1, arg2);

call_user_func_array(array($object, $function_name), array(arg1, arg2));

그러나 $function_name()메소드 를 사용하려는 경우 이름이 동적 인 경우 함수의 존재를 테스트하는 것이 좋습니다.

if(method_exists($object, $function_name))
{
    $object->$function_name(arg1, arg2);
}

13

클래스 내의 메소드에 변수를 사용하려고했기 때문에 Google이 다른 사람을 여기로 데려온 경우 아래는 실제로 작동하는 코드 샘플입니다. 위의 어느 것도 내 상황에 효과가 없었습니다. 주요 차이점은의 &선언 $c = & new...&$c전달에 call_user_func있습니다.

내 구체적인 사례는 색상과 두 가지 멤버 메소드 lighten()와 관련 darken()이 있고 csscolor.php 클래스에서 누군가의 코드를 구현할 때 입니다. 어떤 이유로 든 나는 논리로 선택하지 않고 밝게 또는 어둡게 호출 할 수있는 동일한 코드를 원했습니다. 이것은 if-else를 사용하지 않거나이 메소드를 호출하는 코드를 변경하지 않은 완고한 결과 일 수 있습니다.

$lightdark="lighten"; // or optionally can be darken
$color="fcc";   // a hex color
$percent=0.15;  
include_once("csscolor.php");
$c = & new CSS_Color($color);
$rtn=call_user_func( array(&$c,$lightdark),$color,$percent);

아무것도 시도해도 효과가 $c->{...}없었습니다. 의 php.net 페이지 하단에서 독자가 기고 한 내용을 숙독하면서 위 내용을 정리할 call_user_func수있었습니다. 또한 $params배열로 저에게 효과적이지 않았습니다 .

// This doesn't work:
$params=Array($color,$percent);
$rtn=call_user_func( array(&$c,$lightdark),$params);

위의 시도는 두 번째 인수 (퍼센트)를 예상하는 메소드에 대한 경고를 제공합니다.


"$ c = & new CSS_Color"는 무엇을합니까? 나는 앰프 (&)에 대해 이야기하고 있습니다. 이것은 무엇을 바꾸고 있습니까?
Danon

@danon &은 "주소"또는 "참조"연산자입니다. CSS_Color 클래스의 새 객체를 조작 한 다음 참조 (일명 주소)를 $ c에 할당합니다. 반복 코드가 싫기 때문에 종종 변수 변수 이름을 사용합니다.
Chris K

1
이해가 안 돼요 어쨌든 참조로 객체가 전달되지 않습니까? 내 말은, $ c를 함수에 전달하고 변경하면 원래 객체도 영향을받습니다. 당신이 이것을 사용했는지 여부에 관계없이, 맞습니까?
Danon

다른 기호 조합을 시도했지만 php.org에서 사용자 의견을 읽는 동안에 만 작업 코드를 얻을 수있었습니다. PHP의 행동을 담당하는 사람들과 토론을 시작해야합니다.
Chris K

두 번째로 잘못 읽은 예는 call_user_func_array
Tofandel

13

몇 년 늦었지만 현재는 이것이 가장 좋은 방법입니다.

$x = (new ReflectionFunction("foo"))->getClosure();
$x();

3
OOP 방법은 있지만 아무도 Reflection 클래스를 언급하지 않았기 때문에 +1을주었습니다.
Lajos Meszaros

이 답변을 이해하지 마십시오. 정확히 어떤 문제를 해결하고 있습니까?
David Spector

10

완전성을 위해 eval ()을 사용할 수도 있습니다 .

$functionName = "foo()";
eval($functionName);

그러나 call_user_func()올바른 방법입니다.


8
eval ()은 동일한 동작을 허용하지만 PHP 코드를 실행할 수도 있습니다. 따라서 변수를 사용하여 시스템을 가로 챌 수 있습니다. call_user_func ()는 이러한 보안 문제를 일으키지 않습니다.
John

4
eval이 질문에 대한 해결책이 아닙니다.
ankr

1
공격자가 서버를 완전히 지울 수 있으므로이 작업을 수행하지 마십시오.
andreszs

10

솔루션 : PHP7 사용

참고 : 요약 된 버전은 답변 끝 부분의 TL; DR을 참조하십시오.

오래된 방법

업데이트 : 여기에 설명 된 이전 방법 중 하나가 제거되었습니다. 다른 방법에 대한 설명은 다른 답변을 참조하십시오. 여기에서는 다루지 않습니다. 그건 그렇고,이 답변이 도움이되지 않으면 물건 업그레이드를 반환해야합니다. PHP 5.6 지원은 2019 년 1 월에 종료되었습니다 (현재 PHP 7.0 및 7.1도 지원되지 않음). 자세한 내용은 지원되는 버전 을 참조하십시오.

다른 사람들이 언급했듯이 PHP5 (및 PHP7과 같은 최신 버전)에서는 변수를 함수 이름으로 사용 call_user_func()하고call_user_func_array() (개인적으로는 그 함수를 싫어합니다) 등을 사용할 수 있습니다.

새로운 방법

PHP7부터는 다음과 같은 새로운 방법이 도입되었습니다.

참고 : 내부의 모든 것<something> 대괄호 안에있는 무언가를 형성하는 하나 이상의 표현을 의미합니다.<function_name> 의미합니다. 함수 이름을 형성하는 표현식을 의미합니다.

동적 함수 호출 : 함수 이름 즉석

괄호 안에 하나 이상의 표현식을 함수 이름으로 한 번에 다음과 같은 형식으로 사용할 수 있습니다.

(<function_name>)(arguments);

예를 들면 다음과 같습니다.

function something(): string
{
    return "something";
}

$bar = "some_thing";

(str_replace("_", "", $bar))(); // something

// Possible, too; but generally, not recommended, because makes your code more complicated
(str_replace("_", "", $bar))()(); 

참고 : 괄호를 제거해도 str_replace()오류는 아니지만 괄호를 넣으면 코드를 더 쉽게 읽을 수 있습니다. 그러나 때때로, 예를 들어. 연산자 . 일관성을 유지하려면 항상 괄호를 넣는 것이 좋습니다.

동적 메소드 호출 : 메소드 이름

동적 함수 호출과 마찬가지로 괄호 대신 중괄호로 묶인 메소드 호출과 동일한 방법을 사용할 수 있습니다 (추가 양식의 경우 TL; DR 섹션으로 이동).

$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);

예제에서 참조하십시오 :

class Foo
{
    public function another(): string
    {
        return "something";
    }
}

$bar = "another thing";

(new Something())->{explode(" ", $bar)[0]}(); // something

동적 메소드 호출 : 배열 구문

PHP7에 추가 된보다 우아한 방법은 다음과 같습니다.

[<object>, <method_name>](arguments);
[<class_name>, <method_name>](arguments); // Static calls only

예로서:

class Foo
{
    public function nonStaticCall()
    {
        echo "Non-static call";
    }
    public static function staticCall()
    {
        echo "Static call";
    }
}

$x = new X();

[$x, "non" . "StaticCall"](); // Non-static call
[$x, "static" . "Call"](); // Static call

참고 : 이전 방법보다이 방법을 사용하면 전화 유형에 신경 쓰지 않아도됩니다 (정적인지 여부).

추가 예 : 익명 클래스 사용

상황을 조금 복잡하게 만들려면 익명 클래스 와 위 기능을 조합하여 사용할 수 있습니다 .

$bar = "SomeThing";

echo (new class {
    public function something()
    {
        return 512;
    }
})->{strtolower($bar)}(); // 512

TL; DR (결론)

일반적으로 PHP7에서는 다음 형식을 모두 사용할 수 있습니다.

// Everything inside `<something>` brackets means one or more expressions
// to form something

// Dynamic function call
(<function_name>)(arguments)

// Dynamic method call on an object
$object->{<method_name>}(arguments)
$object::{<method_name>}(arguments)

// Dynamic method call on a dynamically-generated object
(<object>)->{<method_name>}(arguments)
(<object>)::{<method_name>}(arguments)

// Dynamic method call, statically
ClassName::{<method_name>}(arguments)
(<class_name>)::{<method_name>}(arguments)

// Dynamic method call, array-like (no different between static and non-static calls
[<object>, <method_name>](arguments)

// Dynamic method call, array-like, statically
[<class_name>, <method_name>](arguments)

이 PHP 대화를 기반으로 합니다 .


1
멋진 표현 목록도 포함됩니다 :(expressions)->$bar()
Necro

1
@ Necro 감사합니다, 나는 그것을 추가했습니다!
MAChitgarha

8

동적 함수 이름 및 네임 스페이스

네임 스페이스를 사용할 때 동적 함수 이름에 대한 요점을 추가하기 만하면됩니다.

네임 스페이스를 사용하는 경우 함수가 전역 네임 스페이스에있는 경우를 제외하고 다음은 작동하지 않습니다 .

namespace greetings;

function hello()
{
    // do something
}

$myvar = "hello";
$myvar(); // interpreted as "\hello();"

무엇을해야합니까?

call_user_func()대신 사용해야 합니다.

// if hello() is in the current namespace
call_user_func(__NAMESPACE__.'\\'.$myvar);

// if hello() is in another namespace
call_user_func('mynamespace\\'.$myvar);

4

객체의 메소드를 호출하려는 경우 @Chris K의 답변을 보완하려면 클로저를 사용하여 단일 변수를 사용하여 호출 할 수 있습니다.

function get_method($object, $method){
    return function() use($object, $method){
        $args = func_get_args();
        return call_user_func_array(array($object, $method), $args);           
    };
}

class test{        

    function echo_this($text){
        echo $text;
    }
}

$test = new test();
$echo = get_method($test, 'echo_this');
$echo('Hello');  //Output is "Hello"

여기 에 다른 예를 게시했습니다.


4

이 질문과 답변에서 배운 것. 모두 감사합니다!

이 변수와 함수가 있다고 가정 해 봅시다.

$functionName1 = "sayHello";
$functionName2 = "sayHelloTo";
$functionName3 = "saySomethingTo";

$friend = "John";
$datas = array(
    "something"=>"how are you?",
    "to"=>"Sarah"
);

function sayHello()
{
echo "Hello!";
}

function sayHelloTo($to)
{
echo "Dear $to, hello!";
}

function saySomethingTo($something, $to)
{
echo "Dear $to, $something";
}
  1. 인수없이 함수를 호출하려면

    // Calling sayHello()
    call_user_func($functionName1); 

    여보세요!

  2. 인수가 1 개인 함수를 호출하려면

    // Calling sayHelloTo("John")
    call_user_func($functionName2, $friend);

    친애하는 존, 안녕!

  3. 하나 이상의 인수로 함수를 호출하려면 함수 동적으로 호출하고 각 함수에 다른 개수의 인수가있는 경우 유용합니다. 이것은 내가 찾은 (그리고 해결 된) 나의 경우입니다. call_user_func_array열쇠입니다

    // You can add your arguments
    // 1. statically by hard-code, 
    $arguments[0] = "how are you?"; // my $something
    $arguments[1] = "Sarah"; // my $to
    
    // 2. OR dynamically using foreach
    $arguments = NULL;
    foreach($datas as $data) 
    {
        $arguments[] = $data;
    }
    
    // Calling saySomethingTo("how are you?", "Sarah")
    call_user_func_array($functionName3, $arguments);

    사라에게, 어떻게 지내?

예 안녕!



2

다음 코드는 PHP에서 동적 함수를 작성하는 데 도움이 될 수 있습니다. 이제 함수 이름은 변수 '$ current_page'에 의해 동적으로 변경 될 수 있습니다.

$current_page = 'home_page';
$function = @${$current_page . '_page_versions'};
$function = function() {
    echo 'current page';
};
$function();

익명 함수 (예 : 동적 함수)는 변수 함수 (예 : 동적으로 함수 호출 )와 다릅니다 . 또한 $function어떤 이유없이 변수를 교체하고 있습니다 .
MAChitgarha

1

변수에 저장된 이름을 사용하여 함수를 안전하게 호출하는 가장 쉬운 방법은

//I want to call method deploy that is stored in functionname 
$functionname = 'deploy';

$retVal = {$functionname}('parameters');

Laravel에서 마이그레이션 테이블을 동적으로 생성하기 위해 아래와 같이 사용했습니다.

foreach(App\Test::$columns as $name => $column){
        $table->{$column[0]}($name);
}

-4

내 생각에 온 하나의 비 전통적인 접근 방식 은 스스로 작성하는 초 자율 AI를 통해 전체 코드를 생성하지 않는 한 "동적으로"호출하려는 함수가 이미 코드에 정의되어있을 가능성이 높다는 것입니다. 베이스. 문자열을 확인하고 악명 높은 행동을하는 이유는 무엇입니까?ifelse 춤을 추어 소환하여 ... 내 요점을 찾으십시오.

예.

if($functionName == 'foo'){
  foo();
} else if($functionName == 'bar'){
  bar();
}

사다리의 switch-case맛이 좋지 않은 경우 에도 사용할 수 있습니다 ifelse.

나는 " 동적으로 함수 호출 "이 절대적으로 필요한 경우가 있다는 것을 이해 합니다 (자체를 수정하는 재귀 논리처럼 ). 그러나 대부분의 일상적인 사소한 사용 사례는 피할 수 있습니다.

문자열이 사용 가능한 함수 정의와 일치하지 않으면 폴백 함수를 실행할 수있는 기회를 제공하면서 애플리케이션에서 많은 불확실성을 제거합니다. 이모.


변수의 값이 이미 함수의 이름 인 경우 왜 추가 작업을 수행합니까? 또한 함수를 실행하기 전에 PHP에서 함수가 존재하는지 확인하기 위해 확실한 피드백을 얻는 것이 좋습니다. if (method_exists($functionName)) $functionName(); else //exception or handle
Necro

2
그러나 요점은 유효하지만 함수 이름이 동적이므로 논리에서 해당 함수가 현재 상황과 관련이 있는지 여부에 관계없이 해당 이름의 함수가 존재하면 해당 문자열이 실행됩니다. 내 접근 방식은 특정 함수 집합 만 실행될 수 있고 그렇지 않으면 오류가 발생할 수 있습니다. 배열 등으로 단순화 할 수 있습니다.
Mohd Abdul Mujib

-10

나는 왜 그것을 사용 해야하는지 모르겠지만 전혀 나에게 들리지는 않지만 소량의 함수 만 있으면 if / elseif 구문을 사용할 수 있습니다. 직접적인 해결책이 가능한지 모르겠습니다.

$ foo = "bar"와 같은 것; $ test = "foo"; 에코 $$ test;

바를 반환해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.