Menu ▾ ▴

#62 Trouble defining functions in compiled templates

open
nobody
None
5
2004-07-23
2004-07-23
No

Not sure this should be called a 'bug' exactly, but here is
the problem:

I have written a tree tag which needs to write a
function to the compiled template (to recurse through a
tree):

function myfunc(&$root) { ... }

The old behaviour of
ServerDataComponentTag::getDataSourceRefCode()
would return a string like:

$root->children['0010']

which would work find _inside_ the function definition
because '$root' is visible inside the scope of the
function, having been passed in as a parameter (and
given the same name).

Now getDataSourceRefCode returns only a temp variable
(which is assigned/declared in the template during
preGenerate) like:

$G

The problem is if I need to have a {$variable} expanded
inside my function definition as I am generating the tag
output, the following code gets inserted:

$G->get('variable')

But because $G is not visible inside the scope of the
function I get errors like 'call to a method of a non-
object' in the compiled template.

Anyone have any ideas how to get around this, i.e.
properly handle {$variable}, {$^^^othervariable},
{$#rootvariable} within the scope of a function
definition in a compiled template? The only option I can
think of is to pass the desired dataspace, plus _all_
parent dataspaces into the function:

function myfunc(&$root, &$B, &$G, ...) { ... }

but this seems like a pretty ugly hack.

A simple fix of course would be to revert back to the old
behaviour of getDataSpaceRefCode(); however this
would affect (i.e. lengthen) the generated code
everywhere even where this issue is not relevant.

Any other ways to get around this? If any of this is
unclear, please let me know and I'll try to clarify.

Discussion

  • Jason E. Sweat

    Jason E. Sweat - 2004-07-23

    Logged In: YES
    user_id=555352

    I had a similar issue with the cell templates for the
    data:table component. I only dealt with the case of
    component or root level dataspaces. I explicitly pass them
    in as arguments using the same variable names as the render
    function would call them. My code would have the same
    problem as yours dealing with {$^^^var}

     
  • Jason E. Sweat

    Jason E. Sweat - 2004-07-23

    Logged In: YES
    user_id=555352

    Oh, and one more thought that I did not resort to, that you
    might...

    Have the parent code always call your function as :
    child_function(get_defined_vars());

    and do
    function child_function($parent_env) {
    extract($parent_env);
    ...
    }

     
  • Michael van Dam

    Michael van Dam - 2004-07-23

    Logged In: YES
    user_id=604745

    >Oh, and one more thought that I did not resort to, that you
    might...
    >
    >Have the parent code always call your function as :
    >child_function(get_defined_vars());
    >
    >and do
    >function child_function($parent_env) {
    > extract($parent_env);
    > ...
    >}

    Thanks for the idea... so basically this would 'automate' the
    generation of the list of dataspace variables ($root, and temp
    variables) to be passed into the function. Still seems a little
    hackish, but I'm going to go with something like this as I think
    it is the best that can be done without changes to WACT
    handling of DataBindingExpressions.

    One issue: I don't think that 'get_defined_vars' can pass
    stuff by reference -- so there would be a lot of overhead
    copying dataspaces on each function call -- but I think it
    should be possible to find a way to do so.

    I was also worried at first that get_defined_vars would also
    grab all the PHP internal variables on the first call to the
    function, but since WACT templates are defined as functions,
    get_defined_vars won't see all these.

     
  • Michael van Dam

    Michael van Dam - 2004-07-27

    Logged In: YES
    user_id=604745

    Just a quick follow-up:

    What I ended up doing to solve this problem is the following. In the function preGenerate, I have:

    $dataspace =& $this;
    while (!is_null($dataspace)) {
    $var = $dataspace->getDataSourceRefCode();
    $this->function_params[] = $var;
    $dataspace =& $dataspace->getParentDataSource();
    }

    To generate the code for the function header:

    $code->writePHP('function ' . $this->function_name . ' (&' . join(',&',$this->function_params) . ') {');

    To generate a function call:

    $code->writePHP($this->function_name . '(' . join(',', $this->function_params) . ');');

    Works nicely. (As long as getDataSourceRefCode returns a simple variable name, rather than some expression.) Thanks again for the tip!

     

Log in to post a comment.