Call a function by name
An ability to call a function/method by name does not exist in compiled languages. But it exists in plain PHP and is essential in various routing/ORMs and so on.
KPHP does not support calling by a dynamic name, just like any other compiled language. 
 How to achieve the same result?
How is it done in plain PHP?
In PHP, you just call any function by name / any method by name / create a class by name:
$f_name = "...";
$f_name();
$f_name(1, "with", ["arguments"]);    
// and methods
$method_name = "...";
A::$method_name();
call_user_func(['A', $method_name]);
// and classes
$class_name = "...";
new $class_name("constructor", "parameters");  
  This is prohibited in KPHP. All calls, all property access — everything must be statically resolved.
How to achieve this in KPHP?
Think of KPHP as of any other compiled language. For dynamic variables, nothing better than switch-case actually exists.
And this is OK, this is not a drawback. Static call graph makes your code predictable and understandable, you always see all available methods reached out from here.
$func_name = "...";
switch ($func_name) {
case "authenticate":
  authenticate();
  break;
case "logout":
  logout();
  break; 
}
  Compile-time known strings and generics
If $class_name is compile-time known, you are able to create it via new $class_name or call like $class_name::method():
/**
 * @kphp-generic T
 * @param class-string<T> $class_name
 */
function demo($class_name) {
  $obj = new $class_name;         // ok
  $obj->afterCreated();
  $class_name::staticMethod();    // also ok
}
demo(A::class);     // actually, demo<A>('A')
demo(B::class);     // actually, demo<B>('B')
  It works only for compile-time known variables, in generic functions. It can work, because everything is still statically resolved.
Probably, when you are searching for a way to “create any class” or “call any function”, that “any” comes from an input. Hence, generics will not fit your needs.
If so, how do I perform request routing?
Let's say you want your-site.com?page=profile&action=edit to call \UrlHandler\Profile::edit(). You have various classes in \UrlHandler namespace for &page get parameter and every class has a method for &action.
First of all, even in plain PHP, it's a bad idea to do like this:
// bad: primitive url mapping
$class_name = "\\UrlHandler\\" . ucfirst($_GET['page']);
$method_name = $_GET['action'];
$class_name::$method_name();
  Why is it a bad pattern? Take these points under consideration:
- you don't have a full list of all available URLs
- if an action has been renamed, to make old links work you should handle it somewhere
- when an URL requires the user to be logged, you check this in each handler
- when an URL is available only for admins/VPN, you check this in each handler
- when an URL distinguishes GET/POST/etc, you handle this in each handler
“You handle this in each handler” using PHP code is not a good practice — not just because it leads to code duplication — but because you spread the area of responsibility between routing and business logic.
Declarative descriptions are much acceptable than imperative handling.
Having all this, you probably already use a declarative manner:
- Either you write something like this:
Route::get('/profile/edit', ['logged' => true], 'Profile::edit');  
  - Or you use annotations, something like this:
class Profile {
  /**
   * @url-handler logged:true method:get
   */
  static public function edit() { /* ... */  }
}
  - Or you have a schema, JSON/PHP/doesn't matter:
[
  { "url": "/profile_edit", "logged": true, "method": "get", "handler": "Profile::edit" }
]
  All these approaches are similar for the following reasons:
- you use declarative manner, not imperative logic for common handling parts (logged, etc)
- you have a full list of what can be called
- calling by name is OK here — its safeness comes from your source code, it happens only on correct input
Because of (2), you can write a script that generates a switch-case code — and use it instead of (3).
This article tried to address the following:
- either you don’t need calling by name at all,
- or you have 2-3 cases and write switch-case manually,
- or you should have a declarative source, from which you can codegenerate switch-case; if you don’t, you are doing something wrong anyway