开发者

How to Force a Method Call on a Property or Method of an Object in PHP?

开发者 https://www.devze.com 2022-12-15 20:54 出处:网络
In my View (using Zend_View so the the view is an object), I make calls to object properties and methods to p开发者_开发百科opulate the template like so:

In my View (using Zend_View so the the view is an object), I make calls to object properties and methods to p开发者_开发百科opulate the template like so:

<?= $this->user->name ?> // Outputs John Doe
<br/>
<?= $this->user->getCompany()->name ?> // Outputs Acme
<br/>
<?= $this->method() ?> // Outputs foobar

If I make it so that all property requests (like for 'user') go through __get() is there any way that I can catch the subsequent calls so that I can force a method call on the final outputted value? For example so that I could do automatic escaping of output.

As I see it right now, I either have to escape the input as it goes into the database or use compiled templates like Smarty does, or switch to assigning every variable to the View object so that it has direct control to force escaping before outputting the data.


You could use a decorator. See this simplified example:

class ViewObject_Decorator
{
    protected $_decoratedObject;

    protected $_view;

    public function __construct( $object, Zend_View view )
    {
        $this->_decoratedObject = $object;
        $this->_view = $view;
    }

    public function __get( $property )
    {
        return $this->_view->escape( $this->_decoratedObject->$property );
    }

    /*
        maybe implement __call to proxy to decoratedObject methods, etc...
    */
}

Then your proposed __get method (presuming this is a Zend_View method?) would be something like:

public function __get( $property )
{
    // decorate the requested object, and send the view along with it.
    return new ViewObject_Decorator( $this->$property, $this );
}


I started out by saying No. Thats because you cant make the returned value go 'through' __get(), but after thinking realised you could get around it. Personally I think it would be inefficient and would also cause other problems such as getting to $name without the escaping.

To do it you need to use __get($var) in each class and then return the variable after escaping it.

probably very wasteful though I personally would use

<?= $this->user->escaped_name() ?>

in the class for the user and the class representing the company

__get($var){ 
  if ($var == 'name')
     return escape($this->name);
}

This is only one example and assumes $name is a non public member. if its an element in an array suitable indexing into the array will be required eg:

return escape($this->data['name']);

NB: I have no knowledge of zend_views but I assume it won't make any difference

DC


Did you try using Zend_View_Abstract::addFilterPath() and Zend_View_Abstract::addFilter()?

See Output Filters in Zend_View


You could extend the view object and then override the __get() method to escape all output as needed.

You can use:

$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$viewRenderer->setView(new My_View());

to change the view object to the one that you create.


The manual way is to use the escape() view helper in the template directly like this:

<?= $this->escape($this->user->name) ?> // Outputs John Doe
<br/>
<?= $this->escape($this->user->getCompany()->name) ?> // Outputs Acme
<br/>
<?= $this->escape($this->method()) ?> // Outputs foobar

The easiest way to automate it is to use a stream wrapper. Zend Framework provides Zend_View_Stream which is used to automate conversion of short tags to long tags. This is enabled using:

$view->setUseStreamWrapper(true);

You would need to extend it to automatically escape any use of <?=. The code to use within the wrapper is something like this:

$find = '/<?=[ ]*([^;>]*?|[^;?]*?)[; ]*?>/';
$replace = "<?php echo $this->escape($1); ?>";
$this->data = preg_replace($find, $replace, $this->data);

Obviously, using a stream wrapper has some performance implications too.

Further details here:

  • http://framework.zend.com/manual/en/zend.view.html#zend.view.introduction.shortTags
  • http://akrabat.com/zend-framework/a-view-stream-with-zend_view/
  • http://mikenaberezny.com/2006/02/19/symphony-templates-ruby-erb/


Use PHPTAL as your view.

It escapes everything by default (compiles templates to PHP which has all neccessary htmlspecialchars() calls added automatically).

${this/user/getCompany/name} <!-- it's safe! -->
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号