summaryrefslogtreecommitdiff
path: root/framework/TComponentReflection.php
diff options
context:
space:
mode:
Diffstat (limited to 'framework/TComponentReflection.php')
-rw-r--r--framework/TComponentReflection.php195
1 files changed, 195 insertions, 0 deletions
diff --git a/framework/TComponentReflection.php b/framework/TComponentReflection.php
new file mode 100644
index 00000000..aef99e8c
--- /dev/null
+++ b/framework/TComponentReflection.php
@@ -0,0 +1,195 @@
+<?php
+/**
+ * TComponent, TPropertyValue classes
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ *
+ * Global Events, intra-object events, Class behaviors, expanded behaviors
+ * @author Brad Anderson <javalizard@mac.com>
+ *
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2014 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @package System
+ */
+
+/**
+ * TComponentReflection class.
+ *
+ * TComponentReflection provides functionalities to inspect the public/protected
+ * properties, events and methods defined in a class.
+ *
+ * The following code displays the properties and events defined in {@link TDataGrid},
+ * <code>
+ * $reflection=new TComponentReflection('TDataGrid');
+ * Prado::varDump($reflection->getProperties());
+ * Prado::varDump($reflection->getEvents());
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System
+ * @since 3.0
+ */
+class TComponentReflection extends TComponent
+{
+ private $_className;
+ private $_properties=array();
+ private $_events=array();
+ private $_methods=array();
+
+ /**
+ * Constructor.
+ * @param object|string the component instance or the class name
+ * @throws TInvalidDataTypeException if the object is not a component
+ */
+ public function __construct($component)
+ {
+ if(is_string($component) && class_exists($component,false))
+ $this->_className=$component;
+ else if(is_object($component))
+ $this->_className=get_class($component);
+ else
+ throw new TInvalidDataTypeException('componentreflection_class_invalid');
+ $this->reflect();
+ }
+
+ private function isPropertyMethod($method)
+ {
+ $methodName=$method->getName();
+ return $method->getNumberOfRequiredParameters()===0
+ && strncasecmp($methodName,'get',3)===0
+ && isset($methodName[3]);
+ }
+
+ private function isEventMethod($method)
+ {
+ $methodName=$method->getName();
+ return strncasecmp($methodName,'on',2)===0
+ && isset($methodName[2]);
+ }
+
+ private function reflect()
+ {
+ $class=new ReflectionClass($this->_className);
+ $properties=array();
+ $events=array();
+ $methods=array();
+ $isComponent=is_subclass_of($this->_className,'TComponent') || strcasecmp($this->_className,'TComponent')===0;
+ foreach($class->getMethods() as $method)
+ {
+ if($method->isPublic() || $method->isProtected())
+ {
+ $methodName=$method->getName();
+ if(!$method->isStatic() && $isComponent)
+ {
+ if($this->isPropertyMethod($method))
+ $properties[substr($methodName,3)]=$method;
+ else if($this->isEventMethod($method))
+ {
+ $methodName[0]='O';
+ $events[$methodName]=$method;
+ }
+ }
+ if(strncmp($methodName,'__',2)!==0)
+ $methods[$methodName]=$method;
+ }
+ }
+ $reserved=array();
+ ksort($properties);
+ foreach($properties as $name=>$method)
+ {
+ $this->_properties[$name]=array(
+ 'type'=>$this->determinePropertyType($method),
+ 'readonly'=>!$class->hasMethod('set'.$name),
+ 'protected'=>$method->isProtected(),
+ 'class'=>$method->getDeclaringClass()->getName(),
+ 'comments'=>$method->getDocComment()
+ );
+ $reserved['get'.strtolower($name)]=1;
+ $reserved['set'.strtolower($name)]=1;
+ }
+ ksort($events);
+ foreach($events as $name=>$method)
+ {
+ $this->_events[$name]=array(
+ 'class'=>$method->getDeclaringClass()->getName(),
+ 'protected'=>$method->isProtected(),
+ 'comments'=>$method->getDocComment()
+ );
+ $reserved[strtolower($name)]=1;
+ }
+ ksort($methods);
+ foreach($methods as $name=>$method)
+ {
+ if(!isset($reserved[strtolower($name)]))
+ $this->_methods[$name]=array(
+ 'class'=>$method->getDeclaringClass()->getName(),
+ 'protected'=>$method->isProtected(),
+ 'static'=>$method->isStatic(),
+ 'comments'=>$method->getDocComment()
+ );
+ }
+ }
+
+ /**
+ * Determines the property type.
+ * This method uses the doc comment to determine the property type.
+ * @param ReflectionMethod
+ * @return string the property type, '{unknown}' if type cannot be determined from comment
+ */
+ protected function determinePropertyType($method)
+ {
+ $comment=$method->getDocComment();
+ if(preg_match('/@return\\s+(.*?)\\s+/',$comment,$matches))
+ return $matches[1];
+ else
+ return '{unknown}';
+ }
+
+ /**
+ * @return string class name of the component
+ */
+ public function getClassName()
+ {
+ return $this->_className;
+ }
+
+ /**
+ * @return array list of component properties. Array keys are property names.
+ * Each array element is of the following structure:
+ * [type]=>property type,
+ * [readonly]=>whether the property is read-only,
+ * [protected]=>whether the method is protected or not
+ * [class]=>the class where the property is inherited from,
+ * [comments]=>comments associated with the property.
+ */
+ public function getProperties()
+ {
+ return $this->_properties;
+ }
+
+ /**
+ * @return array list of component events. Array keys are event names.
+ * Each array element is of the following structure:
+ * [protected]=>whether the event is protected or not
+ * [class]=>the class where the event is inherited from.
+ * [comments]=>comments associated with the event.
+ */
+ public function getEvents()
+ {
+ return $this->_events;
+ }
+
+ /**
+ * @return array list of public/protected methods. Array keys are method names.
+ * Each array element is of the following structure:
+ * [protected]=>whether the method is protected or not
+ * [static]=>whether the method is static or not
+ * [class]=>the class where the property is inherited from,
+ * [comments]=>comments associated with the event.
+ */
+ public function getMethods()
+ {
+ return $this->_methods;
+ }
+} \ No newline at end of file