Example #1
0
 protected function processClass($class)
 {
     $doc = new ClassDoc();
     $doc->name = $class->getName();
     $doc->loadSource($class);
     $this->_currentClass = $doc->name;
     for ($parent = $class; $parent = $parent->getParentClass();) {
         $doc->parentClasses[] = $parent->getName();
     }
     foreach ($class->getInterfaces() as $interface) {
         $doc->interfaces[] = $interface->getName();
     }
     $doc->isInterface = $class->isInterface();
     $doc->isAbstract = $class->isAbstract();
     $doc->isFinal = $class->isFinal();
     $doc->methods = $this->processMethods($class);
     $doc->properties = $this->processProperties($class);
     $doc->signature = ($doc->isInterface ? 'interface ' : 'class ') . $doc->name;
     if ($doc->isFinal) {
         $doc->signature = 'final ' . $doc->signature;
     }
     if ($doc->isAbstract && !$doc->isInterface) {
         $doc->signature = 'abstract ' . $doc->signature;
     }
     if (in_array('CComponent', $doc->parentClasses)) {
         $doc->properties = array_merge($doc->properties, $this->processComponentProperties($class));
         $doc->events = $this->processComponentEvents($class);
     }
     ksort($doc->properties);
     foreach ($doc->properties as $property) {
         if ($property->isProtected) {
             $doc->protectedPropertyCount++;
         } else {
             $doc->publicPropertyCount++;
         }
         if (!$property->isInherited) {
             $doc->nativePropertyCount++;
         }
     }
     foreach ($doc->methods as $method) {
         if ($method->isProtected) {
             $doc->protectedMethodCount++;
         } else {
             $doc->publicMethodCount++;
         }
         if (!$method->isInherited) {
             $doc->nativeMethodCount++;
         }
     }
     foreach ($doc->events as $event) {
         if (!$event->isInherited) {
             $doc->nativeEventCount++;
         }
     }
     $this->processComment($doc, $class->getDocComment());
     return $doc;
 }
 /**
  * Returns a method for a class by a given name
  *
  * @param   text.doclet.ClassDoc self
  * @param   string name
  * @return  text.doclet.MethodDoc
  * @throws  lang.ElementNotFoundException
  */
 public static function methodNamed(ClassDoc $self, $name)
 {
     foreach ($self->methods as $method) {
         if ($name === $method->name()) {
             return $method;
         }
     }
     raise('lang.ElementNotFoundException', 'No such method ' . $name . ' in ' . $self->name());
 }
Example #3
0
 /** Add a class to this package.
  *
  * @param ClassDoc class
  */
 function addClass(ClassDoc $class)
 {
     if (isset($this->_classes[$class->name()])) {
         $phpdoctor = $this->_root->phpdoctor();
         echo "\n";
         $phpdoctor->warning('Found class ' . $class->name() . ' again, overwriting previous version');
     }
     $this->_classes[$class->name()] = $class;
 }
Example #4
0
 /**
  * Parses a class file and returns a classdoc element
  *
  * @param   string classname fully qualified class name
  * @return  text.doclet.ClassDoc
  * @throws  lang.IllegalArgumentException if class could not be found or parsed
  */
 public function classNamed($classname)
 {
     static $cache = array();
     static $map = array('uses' => self::T_USES, 'define' => self::T_DEFINE);
     // Check cache
     if (isset($cache[$classname])) {
         return $cache[$classname];
     }
     // Check for php namespace - in this case, we have a builtin class. These
     // classes will not be documented for the moment.
     if ('php.' == substr($classname, 0, 4)) {
         return NULL;
     }
     // Find class
     if (!($loader = $this->findClass($classname))) {
         throw new IllegalArgumentException(sprintf('Could not find %s in %s', xp::stringOf($classname), xp::stringOf($this->sourcepath)));
     }
     // Tokenize contents
     $tokens = @token_get_all($loader->loadClassBytes($classname));
     if (!$tokens || T_OPEN_TAG !== $tokens[0][0]) {
         throw new IllegalArgumentException(sprintf('Could not parse "%s" from %s, first token: %s', $classname, xp::stringOf($loader), xp::stringOf($tokens[0])));
     }
     with($doc = new ClassDoc(), $doc->setLoader($loader), $doc->setRoot($this));
     $annotations = $comment = $package = NULL;
     $modifiers = array();
     $state = self::ST_INITIAL;
     for ($i = 0, $s = sizeof($tokens); $i < $s; $i++) {
         $t = $tokens[$i];
         if (is_array($t) && isset($map[$t[1]])) {
             $t[0] = $map[$t[1]];
         }
         switch ($state . $t[0]) {
             case self::ST_INITIAL . T_DOC_COMMENT:
             case self::ST_CLASS_BODY . T_DOC_COMMENT:
                 $comment = $t[1];
                 break;
             case self::ST_INITIAL . T_COMMENT:
             case self::ST_CLASS_BODY . T_COMMENT:
                 if (strncmp('#[@', $t[1], 3) == 0) {
                     $annotations = substr($t[1], 2);
                 } else {
                     if (strncmp('#', $t[1], 1) == 0) {
                         $annotations .= substr($t[1], 1);
                     }
                 }
                 if (']' == substr(rtrim($t[1]), -1)) {
                     $annotations = '[' . trim($annotations);
                 }
                 break;
             case self::ST_INITIAL . T_VARIABLE:
                 if ('$package' === $t[1]) {
                     // RFC #0037: $package= 'lang.reflect';
                     while (T_CONSTANT_ENCAPSED_STRING !== $tokens[$i][0] && $i < $s) {
                         $i++;
                     }
                     $package = trim($tokens[$i][1], '\'"');
                 }
                 break;
             case self::ST_INITIAL . self::T_USES:
                 $state = self::ST_USES;
                 break;
             case self::ST_USES . T_CONSTANT_ENCAPSED_STRING:
                 $cn = trim($t[1], '"\'');
                 if (!$this->findClass($cn)) {
                     throw new IllegalStateException('Could not find used class "' . $cn . '" for class ' . $classname . ' in ' . xp::stringOf($this->sourcepath));
                 }
                 $doc->usedClasses->classes[] = $cn;
                 break;
             case self::ST_USES . ')':
                 $state = self::ST_INITIAL;
                 break;
             case self::ST_INITIAL . self::T_DEFINE:
                 $state = self::ST_DEFINE;
                 break;
             case self::ST_INITIAL . T_NAMESPACE:
                 $package = '';
                 $i += 2;
                 // Eat "namespace"
                 while (';' !== $tokens[$i][0] && $i < $s) {
                     $package .= trim($tokens[$i++][1]);
                 }
                 $package = strtr($package, '\\', '.');
                 break;
             case self::ST_DEFINE . T_CONSTANT_ENCAPSED_STRING:
                 $state = self::ST_DEFINE_VALUE;
                 $define = trim($t[1], '"\'');
                 break;
             case self::ST_DEFINE_VALUE . T_CONSTANT_ENCAPSED_STRING:
             case self::ST_DEFINE_VALUE . T_LNUMBER:
             case self::ST_DEFINE_VALUE . T_DNUMBER:
             case self::ST_DEFINE_VALUE . T_STRING:
                 $doc->constants[$define] = $t[1];
                 break;
             case self::ST_DEFINE_VALUE . ')':
                 $state = self::ST_INITIAL;
                 break;
             case self::ST_INITIAL . T_INTERFACE:
                 $doc->type = INTERFACE_CLASS;
                 // Fall-through intended
             // Fall-through intended
             case self::ST_INITIAL . T_CLASS:
                 while (T_STRING !== $tokens[$i][0] && $i < $s) {
                     $i++;
                 }
                 $name = $tokens[$i][1];
                 if ($package && substr(strtr($name, '·', '.'), 0, strlen($package)) == $package) {
                     $name = substr($name, strlen($package) + 1);
                 }
                 $doc->name = $name;
                 $doc->qualifiedName = $classname;
                 $doc->rawComment = $comment;
                 $doc->annotations = $annotations;
                 $doc->modifiers = $modifiers;
                 $comment = $annotations = NULL;
                 $modifiers = array();
                 $state = self::ST_CLASS;
                 break;
             case self::ST_CLASS . T_EXTENDS:
                 while (T_STRING !== $tokens[$i][0] && $i < $s) {
                     $i++;
                 }
                 $doc->superclass = $this->classNamed($this->qualifyName($doc, $tokens[$i][1]));
                 break;
             case self::ST_CLASS . T_IMPLEMENTS:
                 $state = self::ST_IMPLEMENTS;
                 break;
             case self::ST_IMPLEMENTS . T_STRING:
                 $doc->interfaces->classes[] = $this->qualifyName($doc, $t[1]);
                 break;
             case self::ST_CLASS . '{':
             case self::ST_IMPLEMENTS . '{':
                 $state = self::ST_CLASS_BODY;
                 break;
             case self::ST_CLASS_BODY . T_VARIABLE:
                 $state = self::ST_CLASS_VAR;
                 // Fall-through intended
             // Fall-through intended
             case self::ST_CLASS_VAR . T_VARIABLE:
                 unset($field);
                 $field = new FieldDoc();
                 $field->declaring = $doc;
                 $field->name = $t[1];
                 $field->modifiers = $modifiers;
                 break;
             case self::ST_CLASS_VAR . '=':
                 $state = self::ST_VARIABLE_VALUE;
                 break;
             case self::ST_CLASS_VAR . ',':
                 $doc->fields[] = $field;
                 break;
             case self::ST_CLASS_VAR . ';':
                 $doc->fields[] = $field;
                 $state = self::ST_CLASS_BODY;
                 $modifiers = array();
                 break;
             case self::ST_VARIABLE_VALUE . T_CONSTANT_ENCAPSED_STRING:
             case self::ST_VARIABLE_VALUE . T_LNUMBER:
             case self::ST_VARIABLE_VALUE . T_DNUMBER:
             case self::ST_VARIABLE_VALUE . T_STRING:
                 $field->constantValue = $t[1];
                 $state = self::ST_CLASS_VAR;
                 break;
             case self::ST_VARIABLE_VALUE . T_ARRAY:
                 $brackets = 0;
                 $src = '';
                 do {
                     $t = $tokens[$i];
                     $src .= is_array($t) ? $t[1] : $t;
                     if ('(' == $t[0]) {
                         $brackets++;
                     } else {
                         if (')' == $t[0] and --$brackets <= 0) {
                             break;
                         }
                     }
                 } while (++$i < $s);
                 $field->constantValue = $src;
                 $state = self::ST_CLASS_VAR;
                 break;
                 // Before member declaration (e.g. public static $..., protected function ...)
             // Before member declaration (e.g. public static $..., protected function ...)
             case self::ST_CLASS_BODY . T_PUBLIC:
             case self::ST_CLASS_BODY . T_PRIVATE:
             case self::ST_CLASS_BODY . T_PROTECTED:
             case self::ST_CLASS_BODY . T_STATIC:
             case self::ST_CLASS_BODY . T_FINAL:
             case self::ST_CLASS_BODY . T_ABSTRACT:
                 // Before class declaration (e.g. abstract class ...)
             // Before class declaration (e.g. abstract class ...)
             case self::ST_INITIAL . T_FINAL:
             case self::ST_INITIAL . T_ABSTRACT:
                 $modifiers[$t[1]] = TRUE;
                 break;
             case self::ST_CLASS_BODY . T_FUNCTION:
                 while (T_STRING !== $tokens[$i][0] && $i < $s) {
                     $i++;
                 }
                 with($method = new MethodDoc(), $method->setRoot($this));
                 $method->name = $tokens[$i][1];
                 $method->rawComment = $comment;
                 $method->annotations = $annotations;
                 $method->modifiers = $modifiers;
                 $method->declaring = $doc;
                 // Omit static initializer, it's not a real function
                 if ('__static' != $method->name) {
                     $doc->methods[] = $method;
                 }
                 $comment = $annotations = NULL;
                 $modifiers = array();
                 $state = self::ST_FUNCTION;
                 break;
             case self::ST_FUNCTION . '(':
                 $state = self::ST_FUNCTION_ARGUMENTS;
                 $argument = NULL;
                 break;
             case self::ST_FUNCTION_ARGUMENTS . T_VARIABLE:
                 $argument = $t[1];
                 break;
             case self::ST_FUNCTION_ARGUMENTS . ',':
                 $method->arguments[$argument] = NULL;
                 break;
             case self::ST_FUNCTION_ARGUMENTS . '=':
                 $state = self::ST_ARGUMENT_VALUE;
                 break;
             case self::ST_ARGUMENT_VALUE . T_CONSTANT_ENCAPSED_STRING:
             case self::ST_ARGUMENT_VALUE . T_LNUMBER:
             case self::ST_ARGUMENT_VALUE . T_DNUMBER:
             case self::ST_ARGUMENT_VALUE . T_STRING:
                 $method->arguments[$argument] = $t[1];
                 break;
             case self::ST_ARGUMENT_VALUE . T_ARRAY:
                 $brackets = 0;
                 $src = '';
                 do {
                     $t = $tokens[$i];
                     $src .= is_array($t) ? $t[1] : $t;
                     if ('(' == $t[0]) {
                         $brackets++;
                     } else {
                         if (')' == $t[0] and --$brackets <= 0) {
                             break;
                         }
                     }
                 } while (++$i < $s);
                 $method->arguments[$argument] = $src;
                 break;
             case self::ST_ARGUMENT_VALUE . ',':
                 $state = self::ST_FUNCTION_ARGUMENTS;
                 break;
             case self::ST_ARGUMENT_VALUE . ')':
                 $state = self::ST_FUNCTION;
                 break;
             case self::ST_FUNCTION_ARGUMENTS . ')':
                 $argument && ($method->arguments[$argument] = NULL);
                 $state = self::ST_FUNCTION;
                 break;
             case self::ST_FUNCTION . ';':
                 // Interface and abstract methods have no body
                 $state = self::ST_CLASS_BODY;
                 break;
             case self::ST_FUNCTION . '{':
                 $brackets = 0;
                 do {
                     $c = $tokens[$i][0];
                     if ('{' == $c) {
                         $brackets++;
                     } else {
                         if ('}' == $c and --$brackets <= 0) {
                             break;
                         }
                     }
                 } while (++$i < $s);
                 $state = self::ST_CLASS_BODY;
                 break;
             case self::ST_CLASS_BODY . '}':
                 $state = self::ST_INITIAL;
                 break;
         }
     }
     return $cache[$classname] = $doc;
 }
Example #5
0
 /** Build the class hierarchy tree which is placed at the top of the page.
  *
  * @param RootDoc rootDoc The root doc
  * @param ClassDoc class Class to generate tree for
  * @param int depth Depth of recursion
  * @return mixed[]
  */
 function _buildTree(RootDoc $rootDoc, ClassDoc $class, $depth = NULL)
 {
     if ($depth === NULL) {
         $start = TRUE;
         $depth = 0;
     } else {
         $start = FALSE;
     }
     $output = '';
     $undefinedClass = FALSE;
     if ($class->superclass()) {
         echo "Class:" . $class->_name . " - Superclass: " . $class->superClass() . PHP_EOL;
         $superclass = $rootDoc->classNamed($class->superclass());
         if ($superclass) {
             $result = $this->_buildTree($rootDoc, $superclass, $depth);
             $output .= $result[0];
             $depth = ++$result[1];
         } else {
             $output .= $class->superclass() . '<br>';
             //$output .= str_repeat('   ', $depth).' └─';
             $output .= str_repeat('   ', $depth) . '&lfloor;&nbsp;';
             $depth++;
             $undefinedClass = TRUE;
         }
     }
     if ($depth > 0 && !$undefinedClass) {
         //$output .= str_repeat('   ', $depth).' └─';
         $output .= str_repeat('   ', $depth) . '&lfloor;&nbsp;';
     }
     if ($start) {
         $output .= '<strong>' . $class->name() . '</strong><br />';
     } else {
         $output .= '<a href="' . str_repeat('../', $this->_depth) . $class->asPath() . '">' . $class->name() . '</a><br>';
     }
     return array($output, $depth);
 }
Example #6
0
 /**
  * Generate class documentation for a given class and write it to the
  * given output stream
  *
  * @param   text.doclet.ClassDoc doc
  * @param   io.streams.OutputStream
  * @return  io.streams.OutputStream
  */
 protected function writeDoc(ClassDoc $doc, OutputStream $stream)
 {
     $this->writeHeader($doc->name(), $stream);
     $base = str_repeat('../', substr_count($doc->qualifiedName(), '.'));
     // Summary
     $stream->write('<h4><a href="' . $base . 'index.html">Overview</a>');
     $stream->write(' &#xbb; <a href="summary.html">' . $doc->containingPackage()->name() . '</a></h4>');
     $stream->write('<h1>' . ucfirst($doc->classType()) . ' ' . $doc->name() . '</h1>');
     $stream->write('<dl>');
     if ($doc->isInterface()) {
         $implementations = $this->classesImplementing($doc);
         if (!empty($implementations)) {
             $stream->write('<dt>All known implementing classes:</dt><dd>');
             for ($i = 0, $s = sizeof($implementations); $i < $s; $i++) {
                 $stream->write($this->typeLink($implementations[$i]->qualifiedName(), $base));
                 $i < $s - 1 && $stream->write(', ');
             }
             $stream->write('</dd>');
         }
     } else {
         $implemented = $this->allInterfacesImplementedBy($doc);
         if (!empty($implemented)) {
             $stream->write('<dt>All implemented interfaces:</dt><dd>');
             for ($i = 0, $s = sizeof($implemented); $i < $s; $i++) {
                 $stream->write($this->typeLink($implemented[$i]->qualifiedName(), $base));
                 $i < $s - 1 && $stream->write(', ');
             }
             $stream->write('</dd>');
         }
         $subclasses = $this->directSubclassesOf($doc);
         if (!empty($subclasses)) {
             $stream->write('<dt>Direct known subclasses:</dt><dd>');
             for ($i = 0, $s = sizeof($subclasses); $i < $s; $i++) {
                 $stream->write($this->typeLink($subclasses[$i]->qualifiedName(), $base));
                 $i < $s - 1 && $stream->write(', ');
             }
             $stream->write('</dd>');
         }
     }
     $stream->write('</dl>');
     $stream->write('<hr/>');
     // Signature
     $stream->write('<code>');
     $stream->write(implode(' ', array_keys($doc->getModifiers())) . ' ' . $doc->classType() . ' ' . $doc->name());
     if (!$doc->isInterface()) {
         $doc->superclass && $stream->write(' extends ' . $this->typeLink($doc->superclass->qualifiedName(), $base));
         $implemented = $this->interfacesImplementedBy($doc);
         if (!empty($implemented)) {
             $stream->write(' implements ');
             for ($i = 0, $s = sizeof($implemented); $i < $s; $i++) {
                 $stream->write($this->typeLink($implemented[$i]->qualifiedName(), $base));
                 $i < $s - 1 && $stream->write(', ');
             }
         }
     }
     $stream->write('</code>');
     $this->writeMarkup($doc->commentText(), $stream);
     // Class tags
     $stream->write('<dl>');
     $this->writeTags('See also', $doc->tags('see'), $base, $stream);
     $this->writeTags('Verified by', $doc->tags('test'), $base, $stream);
     $stream->write('</dl>');
     $stream->write('<hr/>');
     // Field summary
     $stream->write('<fieldset><legend>Fields Summary</legend><ul>');
     foreach ($doc->fields as $field) {
         $v = $field->constantValue();
         $stream->write('<li><code>');
         $stream->write($this->isStatic($field) ? 'static ' : '');
         $stream->write($field->name() . ($v ? ' = ' . $v : ''));
         $stream->write('</code><p>' . $this->firstSentence($field->commentText()) . '</p></li>');
     }
     $stream->write('</ul></fieldset>');
     // Method summary
     $stream->write('<fieldset><legend>Method Summary</legend><ul>');
     foreach ($doc->methods as $method) {
         $stream->write('<li><code>');
         $stream->write($this->isStatic($method) ? 'static ' : '');
         $this->writeSignature($method, $base, $stream);
         $stream->write('</code><p>' . $this->firstSentence($method->commentText()) . '</p></li>');
     }
     $stream->write('</ul></fieldset>');
     // Method details
     foreach ($doc->methods as $method) {
         $stream->write('<a name="' . $method->name() . '"><h3>' . $method->name() . '</h3></a>');
         $stream->write('<code>' . implode(' ', array_keys($method->getModifiers())) . ' ');
         $this->writeSignature($method, $base, $stream);
         $stream->write('</code><div class="dfn">');
         $this->writeMarkup($method->commentText(), $stream);
         $stream->write('<dl>');
         $this->writeTags('Parameters', $method->tags('param'), $base, $stream);
         $this->writeTags('Returns', $method->tags('return'), $base, $stream);
         $this->writeTags('Throws', $method->tags('throws'), $base, $stream);
         $this->writeTags('See also', $method->tags('see'), $base, $stream);
         $stream->write('</dl>');
         $stream->write('</div>');
         $stream->write('<hr/>');
     }
     $this->writeFooter($stream);
     return $stream;
 }
Example #7
0
 /**
  * Build the class tree branch for the given element
  *
  * @param ClassDoc[] tree
  * @param ClassDoc element
  */
 function _buildTree(array &$tree, ClassDoc $element)
 {
     $tree[$element->name()] = $element;
     if ($element->superclass()) {
         $rootDoc = $this->_doclet->rootDoc();
         $superclass = $rootDoc->classNamed($element->superclass());
         if ($superclass) {
             $this->_buildTree($tree, $superclass);
         }
     }
 }