2

I'm facing a strange way to call a method on a object.

$controller->{ $action }();

But if i remove the curly braces, the call will work anyway. Someone knows what those curly braces mean?

The current context

<?php
  function call($controller, $action) {
    // require the file that matches the controller name
    require_once('controllers/' . $controller . '_controller.php');

    // create a new instance of the needed controller
    switch($controller) {
      case 'pages':
        $controller = new PagesController();
      break;
    }

    // call the action
    $controller->{ $action }();
  }

  // just a list of the controllers we have and their actions
  // we consider those "allowed" values
  $controllers = array('pages' => ['home', 'error']);

  // check that the requested controller and action are both allowed
  // if someone tries to access something else he will be redirected to the error action of the pages controller
  if (array_key_exists($controller, $controllers)) {
    if (in_array($action, $controllers[$controller])) {
      call($controller, $action);
    } else {
      call('pages', 'error');
    }
  } else {
    call('pages', 'error');
  }
?>

UPDATE

$controller and $action are variables inherited from a index.php file which requires this one. So as inherited variables they are fully accessible.

Here's index.php

//  set default controller and action
$controller =   'login';
$action     =   'index';

//  check if $_GET variables are set
if(isset($_GET['controller']) && $_GET['action'])
{
    //  if we have something set in here we override the default value
    $controller = $_GET['controller'];
    $controller = $_GET['action'];
}

//  now we require the router file who will read the $controller and $action vars.
require_once '../app/core/Router.php';
Caius
  • 2,084
  • 6
  • 31
  • 47

1 Answers1

3

As Dagon linked you to, the method name in that example is a variable variable.

The braces are not required if you are just using a variable name on its own, however if you wanted to concatenate a string into the variable name then you'd need the braces, e.g.:

// These are the same:
$controller->$action();
$controller->{$action}();

// This won't work:
$controller->custom$action();
// This will work:
$controller->{'custom' . $action}();

$action in your example represents a method name, e.g. Run, so you could run $controller->customRun().

In your context, it's an abstracted way of calling a controller's action based on providing $controller and $action.

scrowler
  • 24,273
  • 9
  • 60
  • 92
  • But is it worth to use this type of call in this context? – Caius Jan 25 '16 at 20:34
  • 1
    Absolutely - it's common practice, you just need to validate that the action exists before you call it – scrowler Jan 25 '16 at 20:58
  • @Caius just don't ever remove the `$controller->` part of this, running code like `{ $action }();` is potentially very dangerous. – cmorrissey Jan 25 '16 at 21:02
  • @cmorrissey why would you do that anyway? Surely it'd break the controller system – scrowler Jan 25 '16 at 21:03
  • 1
    @cmorrissey why would i ever have to remove the $controller-> from {$action}(); ? – Caius Jan 25 '16 at 21:04
  • say you removed that to call a function dynamically ... that wasn't in your controller ... then a user types in `?action=phpinfo` ... ooops – cmorrissey Jan 25 '16 at 21:07