function testIt() { $dummy = new DummyObjectX(); $dummy->foo = null; $res = PHPTAL_Context::path($dummy, 'method'); $this->assertEquals('__call', $res); $res = phptal_path($dummy, 'foo'); $this->assertEquals(null, $res); }
/** * Handles variable accesses for the tal path resolver * * @param string $var The variable name to check * * @return Mixed An object/array if the path is not over or a boolean * * @todo replace the PHPTAL_Context::path() with custom code */ public function __get($var) { // When the iterator item is empty we just let the tal // expression consume by continuously returning this // same object which should evaluate to true for 'last' if (is_null($this->data)) { return $this; } // Find the requested variable $value = PHPTAL_Context::path($this->data, $var, true); // Check if it's an object or an array if (is_array($value) || is_object($value)) { // Move the context to the requested variable and return $this->data = $value; $this->addVarName($var); return $this; } // get a hash of the variable contents $hash = md5($value); // compute a path for the variable to use as dictionary key $path = $this->branch . $this->getVarPath() . $var; // If we don't know about this var store in the dictionary if (!isset($this->cache[$path])) { if (!isset($this->dict[$path])) { $this->dict[$path] = $hash; $res = $this->branch === 'F'; } else { // Check if the value has changed if ($this->dict[$path] !== $hash) { $this->dict[$path] = $hash; $res = true; } else { $res = false; } } $this->cache[$path] = $res; } return $this->cache[$path]; }
/** * Resolve TALES path starting from the first path element. * The TALES path : object/method1/10/method2 * will call : $ctx->path($ctx->object, 'method1/10/method2') * * This function is very important for PHPTAL performance. * * This function will become non-static in the future * * @param mixed $base first element of the path ($ctx) * @param string $path rest of the path * @param bool $nothrow is used by phptal_exists(). Prevents this function from * throwing an exception when a part of the path cannot be resolved, null is * returned instead. * * @access private * @return mixed */ public static function path($base, $path, $nothrow = false) { if ($base === null) { if ($nothrow) { return null; } PHPTAL_Context::pathError($base, $path, $path); } foreach (explode('/', $path) as $current) { // object handling if (is_object($base)) { // look for method. Both method_exists and is_callable are required because of __call() and protected methods if (method_exists($base, $current) && is_callable(array($base, $current))) { $base = $base->{$current}(); continue; } // look for property if (property_exists($base, $current)) { $base = $base->{$current}; continue; } if ($base instanceof ArrayAccess && $base->offsetExists($current)) { $base = $base->offsetGet($current); continue; } if ($base instanceof Countable && ($current === 'length' || $current === 'size')) { $base = count($base); continue; } // look for isset (priority over __get) if (method_exists($base, '__isset')) { if ($base->__isset($current)) { $base = $base->{$current}; continue; } } elseif (method_exists($base, '__get')) { $tmp = $base->{$current}; if (null !== $tmp) { $base = $tmp; continue; } } // magic method call if (method_exists($base, '__call')) { try { $base = $base->__call($current, array()); continue; } catch (BadMethodCallException $e) { } } if ($nothrow) { return null; } PHPTAL_Context::pathError($base, $path, $current); } // array handling if (is_array($base)) { // key or index if (array_key_exists((string) $current, $base)) { $base = $base[$current]; continue; } // virtual methods provided by phptal if ($current == 'length' || $current == 'size') { $base = count($base); continue; } if ($nothrow) { return null; } PHPTAL_Context::pathError($base, $path, $current); } // string handling if (is_string($base)) { // virtual methods provided by phptal if ($current == 'length' || $current == 'size') { $base = strlen($base); continue; } // access char at index if (is_numeric($current)) { $base = $base[$current]; continue; } } // if this point is reached, then the part cannot be resolved if ($nothrow) { return null; } PHPTAL_Context::pathError($base, $path, $current); } return $base; }
function testZeroIndex() { $data = array(1, 0, 3); $result = PHPTAL_Context::path($data, '0'); $this->assertEquals(1, $result); }