Include within class and access to $this, self or Static

Asked

Viewed 957 times

19

I found this little code inside the folder Composer/ClassLoader.php, in a project where I use the composer.

 /**
 * Scope isolated include.
 *
 * Prevents access to $this/self from included files.
 */
function includeFile($file)
{
    include $file;
}

The translated comment could be:

Isolated scope for include. Prevents access to $this and self

Testing

Taking into account the case cited above, I realized that in Laravel 4, I have access to $this in any view!

And see what happens in the following code in any view:

@extends('layout.default')
<?php
   $this->compiler = 1;
?>

The following error is generated

Call to a Member Function isExpired() on a non-object

And the interesting detail is that, like the include would be directly in the class method, I was able to access a property of type protected and give it an unexpected value for the framework!

In other frameworks, such as Zend, the $this can also be accessed at view.

Questions

So then I came up with some questions:

  • What would be other possible problems caused by a include within the class and have access to $this - in addition to the aforementioned?

  • In a MVC structure, in the class representing view I should leave free access to $this, or use another class to "be the $this" view, or something else?

  • When it would be recommended to enclose the function include and when not (always, never or in most cases)?

  • 1

    If you think I’ve removed too many tags feel free to add them again =)

  • I believe that in the codes themselves in a project there is no problem in having access to $this because, with some exceptions, we do not use the variable $this in 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.

  • 1

    Here is the commit from the Poser that introduced this function: https://github.com/composer/composer/commit/6d7b9afc4b6bd1bc640b4c2b803c7a87f5a59dd9

  • The problem I see is having access to methods private and protected directly.

  • I will continue to be insistent. I think there is still something missing to solve this question

2 answers

5


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
        )

)
  • 2

    Dude I was looking for this :D was very creative the use of func_get_arg, this deserves +100 :p - Reward on the way!! (When I read up to 7 days I remember Samara kk)

  • @Guilhermenascimento Samara mano ? hahahahaha

  • @Gabrielrodrigues From the movie the so-called, Seven daysssss, I always remember her voice, sometimes I’m still afraid to answer the phone :p

  • @Guilhermenascimento classic the crazy who appears on TV Uhauha

  • @Gabrielrodrigues hehehe himself, the guys answer in http://answall.com/? tab=featured waiting for the 7-day reward should feel the same fear, only in case of losing the reward :)

  • Thank you Mr @Guilhermenascimento. Finally someone agreeing with my nonsense in PHP!

  • Yesterday I tried to play the reward for you, but there were still 4 hours and today I was having fun at the goal :P this already ae, congratulations, it was very creative, even if some do not understand!

Show 2 more comments

3

In fact, Composer uses autoloader to include files based on a directory structure. For example, the class Modules\Db\Adapter, would be in a directory with the PHP file Modules\Db\Adapter.php. The function include would only be used explicitly inside a file if it was an old code that did not contain the autoloading structure, where each file is a class itself.

Access to a method/variable by self (for static variables) and $this (for variables as the object of the class itself), it is only by inheritance (extends) or if the method/variable belongs to the class itself.

The methods accessed by the view through the $this, for example, are methods that are visible public or protected of the same class as View or some method of equal visibility of a class inherited by the class.

  • But we have a problem if a property of View, although protected, is an instance of something else (Helper, for example), and "erase" the instance. Wouldn’t that be a problem? If it wasn’t, I imagine I wouldn’t have why the visibility

  • What do you mean by "delete" the instance? For which an instance would be created to be deleted later?

  • See my example that you will understand. Laravel we have the protected property, which is an instance of Compiler. When assigning a value, it caused an error. That’s what I’m talking about

Browser other questions tagged

You are not signed in. Login or sign up in order to post.