0

I have a view method that accepts 2 arguments, one of them is the data for that view. I have it set as $data as the methods argument.

I'm using the class as follows:

view->make('testview', $movies);

In this case $movies is an object, but it could be just text.

class View {

    public function make($view, $data) {
        require_once("../app/views/$view" . ".php");
        var_dump($data);
    }

}

The thing is, I don't want to use $data->whatever() in all my views because this has no semantic meaning and makes it difficult to review. I would like my view data to have the same name as the variable that I pass to it. In this case I passed the variable $movies to it, so I want to be able to use $movies->whatever() in my view.

In essence I want the variable that I pass to the method to keep the same variable name and be usable like that within the function.

How do I do this?

Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
Stephan-v
  • 19,255
  • 31
  • 115
  • 201
  • Use public function make($view, $movies)? – Erik Dec 01 '14 at 16:00
  • Could you elaborate a little. As @Erik says, just renaming `$data` to `$movies` seems to be it. – Bart Friederichs Dec 01 '14 at 16:01
  • ... except it might not be `$movies` it might be `$badgers` in some views, so a variable variable name in the view files ... I don't really get the point myself, it's just making life difficult. Just use `$data` in all the view files and be done with it, at least you know what the variable will be called in all cases and don't worry about the semantics. If the semantics of a variable name bother you that much just remap it at the top of the view : `$movies = $data;` ugly but it would work. – CD001 Dec 01 '14 at 16:04
  • Exactly like this. I want the reusability when I provide it with a different variable besides $movies. And I'd rather have the variable to be dynamic. It's not making life harder since I have to make a route with the variable to begin with. – Stephan-v Dec 01 '14 at 16:08

5 Answers5

3

You cannot get the name of the variable in the call. What you can do is alike to what template-engines do in this case: do not just assign a variable, but assign it to something.

So you would, for instance

$view = new View();
$view->assign('movies', $movies);
$view->make('testview');

in the assign function you have both the content and the name, so you could make a variable with that name. There's probably a better fix then this, but this can get you started:

function assign($name, $data)
{
    $$name = $data;
    //now you have a $movies in your template
}

This is not a very solid sollution, especially the way you have to require that view. There are many functions you might need to add to get this going, and these are implemented in the more default templating frameworks like e.g. smarty. Take a look if that is something for you, it sounds like you want to create something like that.

Nanne
  • 64,065
  • 16
  • 119
  • 163
  • Thanks, this is what I'm looking for. I just want to automate it to automatically grab the variable name that I pass it though. Seems a bit much to use 2 arguments for the assign method. Just wondering is there is a way of setting the name from the variable that you pass it straight away. – Stephan-v Dec 01 '14 at 16:15
  • @Stephan-v not really - it may be called `$movies` in your script but once to pass it to the object method, the parameter name you're using is `$data` ... `$movies` doesn't exist within the scope of that object method. – CD001 Dec 01 '14 at 16:24
  • note that you can hide this behaviour by using `compact` and `extract` as some of the other answers show, but this is hardly a difference in my opinion. The `assign` way makes you explicitly state what view you use and what variables the view can show. it has the added advantage to strip different functionality from one function. You have a function for your view and one for your data, not a combined one. This should lead to clearer design imho – Nanne Dec 01 '14 at 16:29
  • I've played around with this a bit and it works fine but how would I pass the dynamic variable from the assign() method to the view() method? The view doesn't have access to it otherwise? This would mean I would have to use a dynamic attribute in my class and refer to it using $this in my view method? – Stephan-v Dec 01 '14 at 20:45
  • 1
    you could make a class where you hide all the variables in a key/value type of construction (e.g. plain array) and add a magic getter that calls the array with the specified key? see http://php.net/manual/en/language.oop5.overloading.php#object.get These are the things I was talking about that you'd get 'for free' when using a framework library like smarty – Nanne Dec 01 '14 at 20:49
2

If it's just the name you want to keep track of, you could keep the original $data parameter name but default it to use an array. You would pass the function array('movies'=>$movies) (or array('gerbils'=>$gerbils) if you want) for the $data parameter. That would allow you to keep track of the original variable name without implementing a bunch of extra functions, but you'd have to use $data['movies'] syntax to access it. This has the advantage of being less confusing to future developers who may need to look at your code, too.

J.T. Blum
  • 324
  • 1
  • 9
1

Although you can get the function's argument names dynamically, I think it is not possible to get the passing variable names. Alternatively you could just pass one argument of associate array and extract it in the function.

$param = array(
    'view' => 'testview',
    'movies' => $movies
);
view->make($param);

You could then extract the arguments in the make function.

class View {

    public function make($arg) {
        extract($arg);
        // now you get
        // $view
        // $movies
        require_once("../app/views/$view" . ".php");
        var_dump($movies);
    }
}

Nonetheless, I'm not sure why you want to use $movies or something else in the called function since I guess you want it dynamic and automate.

Community
  • 1
  • 1
Sithu
  • 4,752
  • 9
  • 64
  • 110
  • I just used $movies as an example, I can be replaced by anything of course. Guess I haven't been totally clear on that. – Stephan-v Dec 01 '14 at 16:35
  • @Stephan-v Yes, `$movies` is an example. If the function `make` is dynamic for anything, why you want to use those specific variable names in the function, right? – Sithu Dec 01 '14 at 16:37
0

What you could do is to pass an array and extract() it within your make() method. So the contents of the passed array will be available as variables in the current symbol table.

<?php

// Controller or something

$movies = [
    ['name' => 'Fight Club' => 'rating' => 'great'],
    ['name' => 'The Avengers', 'rating' => 'great'],
    ['name' => 'Iron Man 2',   'rating' => 'sucks'],
];

view->make('testview', compact('movies'));

// View Class

class View {

    public function make($view, $data) {
        extract($data);

        //Usage in Viewfile: $movies[0]['name']
        require_once("../app/views/$view" . ".php");
    }

}

Of course the contents of the passed array do not matter, so you can easily pass around objects, or other things.

thpl
  • 5,810
  • 3
  • 29
  • 43
0

Just as an alternative: if you're using objects for all your data types, and you want to deal with just a single parameter in your method call, you could assign the name of the variable based on the type of object received.

class View {

    public function make($object) {

        //if it's an object - use the type of object to define the variable
        if(is_object($object)) {

            switch(get_class($object)) {

                case 'Movie':
                    $movie = $object;
                    break;

                case 'CD'
                    $cd = $object;
                    break;

                // ... and so on

                default:
                    $data = $object;
                    break;
            }
        }

        //otherwise go with a default of $data
        else {
            $data = $object;
        }
    }

}

I'd personally feel the need to validate the variable with isset() in every view file though, just in case the wrong type of object was passed in - and I fear it would end up with far more validation required in all the view files than necessary.


To go one step further

Alternatively your classes could all extend a common (abstract) class which can hold the type - set that type in the constructor of all your sub-classes and determine the variable name based upon that (set the parent's protected $type; with $this->type = 'movie'; inside the Movie constructor for instance).

This would give you something like this (note: ${$object->getType()} = $object;) which works but I'm not sure about the sanity of it:

class View {

    public function make($object) {

        //if it's an object - use the type of object to define the variable
        //  so for the `Movie` object where the type is 'movie' this will
        //  create a variable called $movie containing the Movie object
        if(is_object($object) && method_exists($object, 'getType')) {

            ${$object->getType()} = $object;
            require_once "/path/to/{$object->getType()}.php";
        }
    }
}

/**
 * base abstract 'thing'
 */
abstract class Thing {

    protected $type;

    public function getType() {
        return $this->type;
    }

}

/**
 * a Movie 'thing'
 */
class Movie extends Thing {

    public function __construct() {
        $this->type = 'movie';
    }

}

//processing stuff
$oView = new View();
$oView->make( new Movie() );
CD001
  • 8,332
  • 3
  • 24
  • 28