In reply to my second question, I would vote in favour of changing the context of the included file, as regards view in the MVC.
And I explain:
As regards the context applied to include given within a class representing a view, had already worked out a solution not long ago - which can be improved by the community :)
Problem
- I have a class, responsible for rendering the
view. However, I want to prevent members of this class from being accessed through $this, but at the same time I want the template that will be rendered to have its own " $this".
Solution
- At the time of rendering, use a
Closure to enclose the included template and at the same time define another object as context for the Closure.
I’ve worked it out as follows:
class View
{
protected $file;
protected $data = [];
public function __construct($file, array $data = [])
{
$this->file = $file;
$this->data = $data;
}
public function render()
{
return $this->createClosureContext();
}
protected function createClosureContext()
{
// Cria parâmetros de fachada apenas para obrigar o tipo de argumento
$caller = function ($file, array $data) {
unset($file, $data);
ob_start();
// Não passa variável, para não colidir com "extract"
extract(func_get_arg(1));
include_once func_get_arg(0);
return ob_get_clean();
};
return $caller->bindTo($this->createObjectContext())->__invoke($this->file, $this->data);
}
protected function createObjectContext()
{
$object = new StdClass;
$object->Html = (object)'Simulate instance of Helper';
return $object;
}
}
Explanation
Like any template class [simple], View receives by parameter the template name and the data that will be sent to the template.
The section where the "magic" in relation to access to $this is here:
protected function createClosureContext()
{
// Cria parâmetros de fachada apenas para obrigar o tipo de argumento
$caller = function ($file, array $data) {
unset($file, $data);
ob_start();
// Não passa variável, para não colidir com "extract"
extract(func_get_arg(1));
include func_get_arg(0);
return ob_get_clean();
};
return $caller->bindTo($this->createObjectContext())->__invoke($this->file, $this->data);
}
I created a closure called $caller and, by the method bindTo, define which object will be used as $this within that Closure. That one Closure is responsible for the inclusion of the.
The object passed in bindTo is a simple stdClass, which could be any object. In this case, I defined it within the method View::createObjectContext().
When we instantiate, we can conclude by testing that the context of $this (for the template included by the view) has been changed accordingly.
Example:
new View('tpl.php', ['nome' => 'Wallace']);
In the template tpl.php:
<?php echo $nome ?>
<?php print_r($this) ?>
Prints:
Wallace
stdClass Object
(
[Html] => stdClass Object
(
[scalar] => Simulate instance of Helper
)
)
If you think I’ve removed too many tags feel free to add them again =)
– Oeslei
I believe that in the codes themselves in a project there is no problem in having access to
$thisbecause, with some exceptions, we do not use the variable$thisin the global scope... However, for code shared between projects it is always important to keep variables and methods that can break the functioning well protected not to suffer unexpected surprises.– Oeslei
Here is the commit from the Poser that introduced this function: https://github.com/composer/composer/commit/6d7b9afc4b6bd1bc640b4c2b803c7a87f5a59dd9
– gmsantos
The problem I see is having access to methods
privateandprotecteddirectly.– Guilherme Nascimento
I will continue to be insistent. I think there is still something missing to solve this question
– Wallace Maxters