Categories > TinyButStrong general >

ArrayAccess and ArrayObject "arrays" and tbs

The forum is closed. Please use Stack Overflow for submitting new questions. Use tags: tinybutstrong , opentbs
By: John Nilsson
Date: 2006-07-20
Time: 12:47

ArrayAccess and ArrayObject "arrays" and tbs

How do you write tbs templates that reads "offstes" from objects that implements ArrayAccess?

I just get TinyButStrong Error in field [x.y...] : item y' is neither a method nor a property in the class 'X'. This message can be cancelled using parameter 'noerr'.
By: Skrol29
Date: 2006-07-20
Time: 14:08

Re: ArrayAccess and ArrayObject "arrays" and tbs

Hi,

This should work (not tested):
[x.offsetGet.y]
By: Skrol29
Date: 2006-07-20
Time: 14:18

Re: ArrayAccess and ArrayObject "arrays" and tbs

Sorry, it should be
[var.x.offsetGet(y)]
(tested)
By: John Nilsson
Date: 2006-07-20
Time: 14:32

Re: ArrayAccess and ArrayObject "arrays" and tbs

Nah, x.offsetGet(y) worked

... but it's not a perfect sollution I'm affraid.

I tried hacking the tbs source instead.

Trying this patch:

--- tbs.php     2006-07-20 14:29:06.000000000 +0200
+++ tbs_class_php5.php  2006-06-25 18:33:22.000000000 +0200
@@ -890,7 +890,7 @@
        if (($SubStart!==false) and $Loc->SubOk) {
                for ($i=$SubStart;$i<$Loc->SubNbr;$i++) {
                        $x = $Loc->SubLst[$i]; // &$Loc... brings an error with Event Example, I don't know why.
-                       if (is_array($Value) || $Value instanceof ArrayAccess) {
+                       if (is_array($Value)) {
                                if (isset($Value[$x])) {
                                        $Value =& $Value[$x];
                                } elseif (array_key_exists($x,$Value)) {// can happens when value is NULL

didn't work to well.

"Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in tbs.php on line 895"

But that is a PHP bug. *sigh*
By: John Nilsson
Date: 2006-07-20
Time: 14:32

Re: ArrayAccess and ArrayObject "arrays" and tbs

Sorry, the patch should be the other way around ofcourse
By: John Nilsson
Date: 2006-07-20
Time: 15:04

Re: ArrayAccess and ArrayObject "arrays" and tbs

This works a little better:

--- tbs_class_php5.php  2006-06-25 18:33:22.000000000 +0200
+++ tbs.php     2006-07-20 15:01:38.000000000 +0200
@@ -899,6 +899,14 @@
                                        if (!isset($Loc->PrmLst['noerr'])) $this->meth_Misc_Alert($Loc,'item \''.$x.'\' is not an existing key in the array.',true);
                                        unset($Value); $Value = ''; break;
                                }
+            } elseif ($Value instanceof ArrayAccess) {
+                if ( $Value->offsetExists($x) ) {
+                    $newVal = $Value->offsetGet($x);
+                    unset($Value); $Value = $newVal;
+                } else {
+                                       if (!isset($Loc->PrmLst['noerr'])) $this->meth_Misc_Alert($Loc,'item \''.$x.'\' is not an existing key in the array.',true);
+                                       unset($Value); $Value = ''; break;
+                }
                        } elseif (is_object($Value)) {
                                $ArgLst = tbs_Misc_CheckArgLst($x);
                                if (method_exists($Value,$x)) {
By: Skrol29
Date: 2006-07-20
Time: 15:18

Re: ArrayAccess and ArrayObject "arrays" and tbs

Something like the following should work too.
But doing this, you avoid any access to other methods of ArrayAccess objects from the template. This can be enhanced, for example, by addind [] around the offset value in order to tell it's an offset value to get.
            } elseif (is_object($Value)) {
++ if ($Value instanceof ArrayAccess) {
++   $x =& $Value->offsetGet($x);
++ } else {
                $ArgLst = tbs_Misc_CheckArgLst($x);
                if (method_exists($Value,$x)) {
                    $x = call_user_func_array(array(&$Value,$x),$ArgLst);
                } elseif (property_exists($Value,$x)) {
                    $x =& $Value->$x;
                } else {
                    if (!isset($Loc->PrmLst['noerr'])) $this->meth_Misc_Alert($Loc,'item '.$x.'\' is neither a method nor a property in the class \''.get_class($Value).'\'.',true);
                    unset($Value); $Value = ''; break;
                }
++ }
                $Value =& $x; unset($x); $x = '';
By: John Nilsson
Date: 2006-07-20
Time: 18:00

Re: ArrayAccess and ArrayObject "arrays" and tbs

I'm working on a slight modification.

Dilemma: If (substr($x,-1,1)!==')') && offsetExists($x) && method_exists($x) ... which takes precedence?

I guess it's intentional that the current semantics treats x.y() the same as x.y

I suggest that x.y should fail if y is not a property or a valid offset, like this:
            } elseif (is_object($Value)) {
                if (substr($x,-1,1)===')') {
                    $ArgLst = tbs_Misc_CheckArgLst($x);
                    if (method_exists($Value,$x)) {
                        $x = call_user_func_array(array(&$Value,$x),$ArgLst);
                    } else {
                        if (!isset($Loc->PrmLst['noerr'])) $this->meth_Misc_Alert($Loc,'item '.$x.'\' is not a method in the class \''.get_class($Value).'\'.',true);
                        unset($Value); $Value = ''; break;
                    }
                } else {
                    if ($Value instanceof ArrayAccess && $Value->offsetExists($x)) {
                        $x =& $Value->offsetGet($x);
                    } elseif (property_exists($Value,$x)) {
                        $x =& $Value->$x;
                    } elseif ($Value instanceof ArrayAccess) {
                        if (!isset($Loc->PrmLst['noerr'])) $this->meth_Misc_Alert($Loc,'item \''.$x.'\' is neither an existing arraykey nor a property in the class \''.get_class($Value).'\'.',true);
                        unset($Value); $Value = ''; break;
                    } else {
                        if (!isset($Loc->PrmLst['noerr'])) $this->meth_Misc_Alert($Loc,'item '.$x.'\' is not a property in the class \''.get_class($Value).'\'.',true);
                        unset($Value); $Value = ''; break;
                    }
                }
                $Value =& $x; unset($x); $x = '';

By: Skrol29
Date: 2006-07-20
Time: 18:26

Re: ArrayAccess and ArrayObject "arrays" and tbs

> ... which takes precedence?

In case of series of expressions separated by AND, PHP proceeds from left to right and breaks as soon as a false expression is met, without evaluating next ones. I hope this answer your question.

There is a problem with your upgraded version for TBS tags. If you do :
[var.AccObj.count]
(having $AccObj as an AccessObject variable)
And if 'count' is an existing setoff, then it will display $AccObj->setoffGet('count'), and makes $AccObj->count unreachable.
And that will be the same for all properties and methods of an AccessObject variable.
By: John Nilsson
Date: 2006-07-20
Time: 18:53

Re: ArrayAccess and ArrayObject "arrays" and tbs

Actually, that was the purpose of my first question. How should this dilemma be solved? I allready knew th precedence rules of the &&-operator ;)

I can't se anyway to solve this dilemma without introducing some new syntax rules for tbs. My version means

given x.y, y will never be treated as a method
if y is both an arraykey offset, and a property, the arraykey offset takes precedence.

Rationale: If y is a property, there is a fair chance that that property is reference by offsetGet, maybe with som additional logic, so prefer offsetGet.