71

Please could someone experienced in PHP help out with the following. Somewhere in my code, I have a call to a public static method inside a non-instantiated class:

$result = myClassName::myFunctionName();

However, I would like to have many such classes and determine the correct class name on the fly according to the user's language. In other words, I have:

$language = 'EN';

... and I need to do something like:

$result = myClassName_EN::myFunctionName();

I know I could pass the language as a parameter to the function and deal with it inside just one common class but for various reasons, I would prefer a different solution.

Does this make any sense, anyone? Thanks.

Ben James
  • 121,135
  • 26
  • 193
  • 155
Tom
  • 30,090
  • 27
  • 90
  • 124
  • 1
    To answer your last 3 lines, no it doesn't make much sense, unless you have a specific reason why you can't implement the "pass language as parameter" way – Matteo Riva Jan 21 '10 at 11:51
  • 3
    Yes, I've got a specific reason... Relates to managing translations in a more sane way for various things that happen inside those classes. It's complicated :) – Tom Jan 21 '10 at 12:05

9 Answers9

124

Use the call_user_func function:

http://php.net/manual/en/function.call-user-func.php

Example:

call_user_func('myClassName_' . $language . '::myFunctionName');
Ben Everard
  • 13,652
  • 14
  • 67
  • 96
  • 29
    Combined with `is_callable` and `method_exists` this would be my recommandation as well. To pass params look at `call_user_func_array` http://php.net/is_callable http://php.net/method_exists http://php.net/call_user_func_array – nikc.org Jan 21 '10 at 11:38
  • This sort of works and seems like the cleanest solution. Thanks – Tom Jan 21 '10 at 11:49
  • @nikc.org You can also pass parameters directly to ``call_user_func()`` if compiling them into an array is inconvenient. – btleffler May 08 '14 at 18:41
  • Is there a way to do this using ReflectionMethod class? – Felipe Francisco Jan 21 '16 at 03:17
  • 1
    It should be noted that you can also format it like this: `call_user_func(['myClassName_' . $language, 'myFunctionName']);` – Josh Foskett Mar 29 '17 at 16:51
34

I think you could do:

$classname = 'myClassName_' . $language;
$result = $classname::myFunctionName();

This is called Variable Functions

Adam Hopkinson
  • 28,281
  • 7
  • 65
  • 99
  • For me, this is the best solution. And according to my bench, this is the quickest too : 100.000 iterations took 0.28s with direct call, 0.32 with this solution, and 0.47 with call_user_func – fred727 Dec 11 '15 at 14:55
  • sometimes we need a fully qualified class name then use this way to add the namespace in the class $className = '\\QuickBooksOnline\\API\Facades\\'.$resource; $postPayload = $className::create(); – Amitesh Bharti Oct 07 '21 at 12:05
16

I would encapsulate the creation of the class you need in a factory.

This way you will have a single entry point when you need to change your base name or the rules for mapping the language to the right class.

    class YourClassFactory {

        private $_language;
        private $_basename = 'yourclass';

        public YourClassFactory($language) {
            $this->_language = $language;
        }

        public function getYourClass() {
            return $this->_basename . '_' . $this->_language;
        }    
    } 

and then, when you have to use it:

$yourClass = $yourClassFactoryInstance->getYourClass();
$yourClass::myFunctionName();
Darryl Hein
  • 142,451
  • 95
  • 218
  • 261
Silvio Donnini
  • 3,233
  • 2
  • 28
  • 29
  • Here more info how the Factory Method Design Pattern works: https://www.sitepoint.com/understanding-the-factory-method-design-pattern/ – Uncoke May 04 '19 at 04:15
9

As temuri said, parse error is produced, when trying '$className::functionName' :

Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM ...

In my case (static method with 2 arguments), best solutions is to use call_user_func_array with 2 arrays (as suggested by nikc.org):

$result = call_user_func_array(array($className, $methodName), array($ard1, $arg2));

BR

Dimcho
  • 143
  • 3
  • 8
7

although i think the way you deal is a very bad idea, i think i may have a solution

$className = 'myClassName_'.$language;
$result = $className::myFunctionName();

i think this is what you want

ahmetunal
  • 3,930
  • 1
  • 23
  • 26
  • Please could you tell me why it's such a bad idea? – Tom Jan 21 '10 at 11:33
  • you can use language as a parameter, instead you choose to define a new class for it. Say you wanna support 200 different languages, will you sit and write 200 different classes. Also it will make your code extremely difficult to read and understand. – ahmetunal Jan 21 '10 at 11:40
  • 1
    Ah.... no there won't be 200 languages. It's a conscious downgrade of good practice to get something else done in a more practical way. – Tom Jan 21 '10 at 11:48
  • 3
    just a note: this works only since php 5.3 - better check if your host provider supports that version (the one I'm using doesn't). – Nick Redmark Jul 16 '11 at 09:47
4

You can easily do next:

<?php

class B {

    public static $t = 5;

    public static function t($h) {
        return "Works!" . $h;
    }
}

$g = 't';
$class = 'B';

echo $class::$g('yes'); //Works! Yes

And it will works fine, tested on PHP 5.2 >=

KorbenDallas
  • 944
  • 9
  • 16
1

As far as i could understand your question, you need to get the class name which can be done using get_class function. On the other hand, the Reflection class can help you here which is great when it comes to methods, arguments, etc in OOP way.

Sarfraz
  • 377,238
  • 77
  • 533
  • 578
0

Solutions like:

$yourClass::myFunctionName();

will not work. PHP will produce parse error.

Unfortunately, the only way is to use very slow call_user_func().

Taryn
  • 242,637
  • 56
  • 362
  • 405
temuri
  • 2,767
  • 5
  • 41
  • 63
-1

I know it's an old thread, but as of PHP 5.3.0 you should be using forward_static_call

$result = forward_static_call(array('myClassName_EN', 'myFunctionName'));

Using your $language variable, it might look like:

$result = forward_static_call(array('myClassName_' . $language, 'myFunctionName'));
Beau
  • 1,771
  • 1
  • 15
  • 20
  • Won't work. Calls a user defined function or method given by the function parameter, with the following arguments. This function must be called within a method context, it can't be used outside a class... as mentioned in http://php.net/manual/en/function.forward-static-call.php – Olivier de Jonge Dec 15 '14 at 16:21