protected function accessValue(array $parts, InspectedValue $inspection, $inspect = false) { for ($max = count($parts) - 1, $i = 0; $i <= $max; $i++) { // Method call (with arguments): if (is_array($parts[$i])) { if (!is_object($inspection->value)) { if ($inspection->useDefaultValue) { $inspection->value = $inspection->defaultValue; return $inspection; } if ($this->accessPolicy == self::ACCESS_POLICY_THROW_EXCEPTION) { throw new ExpressionValueAccessException(sprintf('Cannot call method "%s" on non-object within path "%s"', $parts[$i][0], ExpressionContext::flattenPath($parts))); } $inspection->value = NULL; return $inspection; } $methodName = $parts[$i][0]; if (!method_exists($inspection->value, $methodName)) { if ($inspection->useDefaultValue) { $inspection->value = $inspection->defaultValue; return $inspection; } if ($this->accessPolicy == self::ACCESS_POLICY_THROW_EXCEPTION) { throw new ExpressionValueAccessException(sprintf('Method "%s" is not defined for object of type %s within path "%s"', $methodName, get_class($inspection->value), ExpressionContext::flattenPath($parts))); } $inspection->value = NULL; return $inspection; } if (!is_callable([$inspection->value, $methodName])) { if ($inspection->useDefaultValue) { $inspection->value = $inspection->defaultValue; return $inspection; } if ($this->accessPolicy == self::ACCESS_POLICY_THROW_EXCEPTION) { throw new ExpressionValueAccessException(sprintf('Cannot call invisible method "%s" on object of type %s within path "%s"', $methodName, get_class($inspection->value), ExpressionContext::flattenPath($parts))); } $inspection->value = NULL; return $inspection; } if ($inspect && $i === $max) { $inspection->container = $inspection->value; $inspection->inspect = true; $inspection->name = $methodName; $inspection->resolved = true; $inspection->method = new \ReflectionMethod(get_class($inspection->value), $methodName); } $inspection->value = $inspection->value->{$methodName}(...$parts[$i][1]); if ($i !== $max) { continue; } return $inspection; } // Specialized handling of "this". if ($parts[$i] === 'this') { $inspection->value = $this; if ($i !== $max) { continue; } return $inspection; } // Standard property access using resolvers. $inspection->container = $inspection->value; $inspection->name = $parts[$i]; $inspection->inspect = $inspect && $i === $max; // PHP array if (is_array($inspection->value)) { if (array_key_exists($parts[$i], $inspection->value)) { $inspection->value = $inspection->value[$parts[$i]]; if ($i !== $max) { continue; } $inspection->resolved = true; return $inspection; } } // Specialized access via interface. if ($inspection->value instanceof ExpressionAccessInterface) { if ($inspection->value->resolveExpressionValue($inspection)) { if ($i !== $max) { continue; } $inspection->resolved = true; return $inspection; } } // ArrayAccess: if ($inspection->value instanceof \ArrayAccess) { if ($inspection->value->offsetExists($parts[$i])) { $inspection->value = $inspection->value->offsetGet($parts[$i]); if ($i !== $max) { continue; } $inspection->resolved = true; return $inspection; } } // Access via fields and properties. if (is_object($inspection->value)) { if (array_key_exists($parts[$i], (array) $inspection->value)) { $inspection->field = new \ReflectionProperty(get_class($inspection->value), $parts[$i]); $inspection->value = $inspection->value->{$parts[$i]}; if ($i !== $max) { continue; } $inspection->resolved = true; return $inspection; } if (method_exists($inspection->value, 'get' . $parts[$i])) { $inspection->method = new \ReflectionMethod(get_class($inspection->value), 'get' . $parts[$i]); $inspection->value = $inspection->value->{'get' . $parts[$i]}(); if ($i !== $max) { continue; } $inspection->resolved = true; return $inspection; } if (method_exists($inspection->value, 'is' . $parts[$i])) { $inspection->method = new \ReflectionMethod(get_class($inspection->value), 'is' . $parts[$i]); $inspection->value = $inspection->value->{'is' . $parts[$i]}(); if ($i !== $max) { continue; } $inspection->resolved = true; return $inspection; } if (method_exists($inspection->value, '__get')) { $inspection->value = $inspection->value->{$parts[$i]}; if ($i !== $max) { continue; } $inspection->resolved = true; return $inspection; } } if ($inspection->useDefaultValue) { $inspection->value = $inspection->defaultValue; return $inspection; } if ($this->accessPolicy == self::ACCESS_POLICY_RETURN_NULL) { $inspection->value = NULL; return $inspection; } $type = is_object($inspection->value) ? get_class($inspection->value) : gettype($inspection->value); throw new ExpressionValueAccessException(sprintf('Unable to access property "%s" of %s within path "%s"', $parts[$i], $type, ExpressionContext::flattenPath($parts))); } throw new ExpressionValueAccessException('Cannot access property without a name'); }
/** * {@inheritdoc} */ public function createContext($data = NULL) : ExpressionContextInterface { $context = new ExpressionContext($this, $data); $context->setAccessPolicy($this->defaultAccessPolicy); return $context; }