1<?php
2/**
3 * This file is part of the static reflection component.
4 *
5 * PHP Version 5
6 *
7 * Copyright (c) 2009-2011, Manuel Pichler <mapi@pdepend.org>.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 *   * Redistributions of source code must retain the above copyright
15 *     notice, this list of conditions and the following disclaimer.
16 *
17 *   * Redistributions in binary form must reproduce the above copyright
18 *     notice, this list of conditions and the following disclaimer in
19 *     the documentation and/or other materials provided with the
20 *     distribution.
21 *
22 *   * Neither the name of Manuel Pichler nor the names of his
23 *     contributors may be used to endorse or promote products derived
24 *     from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 *
39 * @category  PHP
40 * @package   pdepend\reflection\api
41 * @author    Manuel Pichler <mapi@pdepend.org>
42 * @copyright 2009-2011 Manuel Pichler. All rights reserved.
43 * @license   http://www.opensource.org/licenses/bsd-license.php  BSD License
44 * @version   SVN: $Id$
45 * @link      http://pdepend.org/
46 */
47
48namespace pdepend\reflection\api;
49
50/**
51 * Static interface implementation.
52 *
53 * @category  PHP
54 * @package   pdepend\reflection\api
55 * @author    Manuel Pichler <mapi@pdepend.org>
56 * @copyright 2009-2011 Manuel Pichler. All rights reserved.
57 * @license   http://www.opensource.org/licenses/bsd-license.php  BSD License
58 * @version   Release: @package_version@
59 * @link      http://pdepend.org/
60 */
61class StaticReflectionInterface extends \ReflectionClass
62{
63    const TYPE = __CLASS__;
64
65    /**
66     * Common zend engine constants
67     */
68    const ZEND_ACC_INTERFACE = 0x80;
69
70    /**
71     * @var string
72     */
73    private $_name = null;
74
75    /**
76     * Doc comment for the reflected interface.
77     *
78     * @var string
79     */
80    private $_docComment = false;
81
82    /**
83     * The file pathname where this interface is defined.
84     *
85     * @var string
86     */
87    private $_fileName = null;
88
89    /**
90     * The start line number where the interface declaration starts.
91     *
92     * @var integer
93     */
94    private $_startLine = -1;
95
96    /**
97     * The end line number where the interface declaration ends.
98     *
99     * @var integer
100     */
101    private $_endLine = -1;
102
103    /**
104     * Declared interface methods.
105     *
106     * @var array(\ReflectionMethod)
107     */
108    private $_methods = null;
109
110    /**
111     * Declared class/interface constants.
112     *
113     * @var array(string=>mixed)
114     */
115    private $_constants = null;
116
117    /**
118     * Extended/Implemented interfaces.
119     *
120     * @var array(\ReflectionClass)
121     */
122    private $_interfaces = null;
123
124    /**
125     * Constructs a new static reflection interface instance.
126     *
127     * @param string $name       Qualified name of the reflected interface.
128     * @param string $docComment Doc comment for this interface.
129     */
130    public function __construct( $name, $docComment )
131    {
132        $this->_setName( $name );
133        $this->_setDocComment( $docComment );
134    }
135
136    /**
137     * Returns the file pathname where this interface was defined.
138     *
139     * @return string
140     */
141    public function getFileName()
142    {
143        return $this->_fileName;
144    }
145
146    /**
147     * Sets the file pathname where this interface was defined. Note that this
148     * method is only for internal use.
149     *
150     * @param string $fileName File pathname where the interface was defined.
151     *
152     * @return void
153     * @access private
154     */
155    public function initFileName( $fileName )
156    {
157        if ( $this->_fileName === null )
158        {
159            $this->_fileName = $fileName;
160        }
161        else
162        {
163            throw new \LogicException( 'Property fileName already set.' );
164        }
165    }
166
167    /**
168     * Returns the qualified name of the reflected interface.
169     *
170     * @return string
171     */
172    public function getName()
173    {
174        return $this->_name;
175    }
176
177    /**
178     * Sets the qualified name of the reflected interface.
179     *
180     * @param string $name The full qualified interface name.
181     *
182     * @return void
183     */
184    private function _setName( $name )
185    {
186        $this->_name = ltrim( $name, '\\' );
187    }
188
189    /**
190     * Returns the short name of the class, the part without the namespace.
191     *
192     * @return string
193     */
194    public function getShortName()
195    {
196        if ( ( $pos = strrpos( $this->_name, '\\' ) ) === false )
197        {
198            return $this->_name;
199        }
200        return substr( $this->_name, $pos + 1 );
201    }
202
203    /**
204     * Returns the namespace name of the reflected interface.
205     *
206     * @return string
207     */
208    public function getNamespaceName()
209    {
210        if ( ( $pos = strrpos( $this->_name, '\\' ) ) === false )
211        {
212            return '';
213        }
214        return substr( $this->_name, 0, $pos );
215    }
216
217    /**
218     * Checks if this class is defined in a namespace.
219     *
220     * @return boolean
221     */
222    public function inNamespace()
223    {
224        return ( $this->getNamespaceName() !== '' );
225    }
226
227    /**
228     * Returns the doc comment for the reflected interface or <b>false</b> when
229     * no doc comment exists.
230     *
231     * @return string|boolean
232     */
233    public function getDocComment()
234    {
235        return $this->_docComment;
236    }
237
238    /**
239     * Sets the doc comment for the reflected interface.
240     *
241     * @param string $docComment Doc comment for this interface.
242     *
243     * @return void
244     */
245    private function _setDocComment( $docComment )
246    {
247        if ( trim( $docComment ) === '' )
248        {
249            $this->_docComment = false;
250        }
251        else
252        {
253            $this->_docComment = $docComment;
254        }
255    }
256
257    /**
258     * Returns the class/interface modifiers
259     *
260     * @return integer
261     */
262    public function getModifiers()
263    {
264        return self::ZEND_ACC_INTERFACE;
265    }
266
267    /**
268     * Returns <b>true</b> when the class is declared abstract or is an interface.
269     *
270     * @return boolean
271     */
272    public function isAbstract()
273    {
274        return true;
275    }
276
277    /**
278     * Returns <b>true</b> when the class is declared as final.
279     *
280     * @return boolean
281     */
282    public function isFinal()
283    {
284        return false;
285    }
286
287    /**
288     * Returns <b>true</b> when the reflected interface/class is an interface,
289     * in this case it means that this method always returns <b>true</b>.
290     *
291     * @return boolean
292     */
293    public function isInterface()
294    {
295        return true;
296    }
297
298    /**
299     * Checks whether the class is internal, as opposed to user-defined.
300     *
301     * @return boolean
302     */
303    public function isInternal()
304    {
305        return false;
306    }
307
308    /**
309     * Checks whether the class is user-defined, as opposed to internal.
310     *
311     * @return boolean
312     */
313    public function isUserDefined()
314    {
315        return true;
316    }
317
318    /**
319     * Checks if a class is an instance of an object.
320     *
321     * @param object $object The object to check.
322     *
323     * @return boolean
324     */
325    public function isInstance( $object )
326    {
327        return ( $object instanceof $this->_name );
328    }
329
330    /**
331     * Checks if the class is instantiable.
332     *
333     * @return boolean
334     */
335    public function isInstantiable()
336    {
337        return false;
338    }
339
340    /**
341     * This method will return <b>true</b> when the reflected object is a class
342     * and implements the interface <b>Traversable</b>.
343     *
344     * @return boolean
345     */
346    public function isIterateable()
347    {
348        return false;
349    }
350
351    /**
352     * Checks that the reflected interface is a child of the given class name.
353     *
354     * @param string $class Name of the searched class.
355     *
356     * @return boolean
357     */
358    public function isSubclassOf( $class )
359    {
360        $interfaceNames = array_map( 'strtolower', $this->getInterfaceNames() );
361        return in_array( ltrim( strtolower( $class ), '\\' ), $interfaceNames );
362    }
363
364    /**
365     * Return <b>true</b> when a constant with the given name exists in the
366     * reflected interface or one of its parents.
367     *
368     * @param string $name Name of the search constant.
369     *
370     * @return boolean
371     */
372    public function hasConstant( $name )
373    {
374        return array_key_exists( $name, $this->getConstants() );
375    }
376
377    /**
378     * Returns the value of a constant for the given <b>$name</b> or <b>false</b>
379     * when no matching constant exists.
380     *
381     * @param string $name Name of the searched constant.
382     *
383     * @return mixed
384     */
385    public function getConstant( $name )
386    {
387        if ( $this->hasConstant( $name ) )
388        {
389            $constants = $this->getConstants();
390            return $constants[$name];
391        }
392        return false;
393    }
394
395    /**
396     * Returns an array with constants defined in this or one of its parent
397     * classes.
398     *
399     * @return array(string=>mixed)
400     */
401    public function getConstants()
402    {
403        return $this->_collectConstants( $this, (array) $this->_constants );
404    }
405
406    /**
407     * Collects all constants from the given class when they are not present in
408     * the given <b>$result</b> array.
409     *
410     * @param \ReflectionClass     $class  The context class.
411     * @param array(string=>mixed) $result Previous collected constants
412     *
413     * @return array(string=>mixed)
414     */
415    private function _collectConstants( \ReflectionClass $class, array $result )
416    {
417        foreach ( $class->getInterfaces() as $interface )
418        {
419            foreach ( $interface->getConstants() as $name => $value )
420            {
421                if ( array_key_exists( $name, $result ) === false )
422                {
423                    $result[$name] = $value;
424                }
425            }
426        }
427        return $result;
428    }
429
430    /**
431     * Initializes the declared constants for the reflected class/interface.
432     *
433     * @param array(string=>mixed) $contants Declared class/interface constants.
434     *
435     * @return void
436     * @access private
437     */
438    public function initConstants( array $contants )
439    {
440        if ( $this->_constants === null )
441        {
442            $this->_constants = $contants;
443        }
444        else
445        {
446            throw new \LogicException( 'Property constants already set' );
447        }
448    }
449
450    /**
451     * Checks whether it implements an interface.
452     *
453     * @param string $interface The interface name.
454     *
455     * @return boolean
456     */
457    public function implementsInterface( $interface )
458    {
459        if ( strcasecmp( $this->_name, $interface ) === 0 )
460        {
461            return true;
462        }
463        return in_array(
464            strtolower( $interface ),
465            array_map( 'strtolower', $this->getInterfaceNames() )
466        );
467    }
468
469    /**
470     * Returns an array with the names of all implemented/extended interfaces.
471     *
472     * @return array(string)
473     */
474    public function getInterfaceNames()
475    {
476        $names = array();
477        foreach ( $this->getInterfaces() as $interface )
478        {
479            $names[] = $interface->getName();
480        }
481        return $names;
482    }
483
484    /**
485     * Returns an array with all implemented/extended interfaces.
486     *
487     * @return array(\ReflectionClass)
488     */
489    public function getInterfaces()
490    {
491        return array_values( $this->_collectInterfaces( (array) $this->_interfaces ) );
492    }
493
494    /**
495     * Collects recursive all implemented/extended interfaces.
496     *
497     * @param array(\ReflectionClass)         $interfaces    Input interface list.
498     * @param array(string=>\ReflectionClass) $interfaceList Result list
499     *
500     * @return array(\ReflectionClass)
501     */
502    private function _collectInterfaces( array $interfaces, array &$interfaceList = array() )
503    {
504        foreach ( $interfaces as $interface )
505        {
506            if ( isset( $interfaceList[$interface->getName()] ) === false )
507            {
508                $interfaceList[$interface->getName()] = $interface;
509                $this->_collectInterfaces( $interface->getInterfaces(), $interfaceList );
510            }
511        }
512        return $interfaceList;
513    }
514
515    /**
516     * Initializes the parent interfaces of this interface instance.
517     *
518     * @param array(\ReflectionClass) $interfaces List of parent interfaces.
519     *
520     * @return void
521     * @access private
522     */
523    public function initInterfaces( array $interfaces )
524    {
525        if ( $this->_interfaces === null )
526        {
527            $this->_interfaces = $interfaces;
528        }
529        else
530        {
531            throw new \LogicException( 'Interfaces already set' );
532        }
533    }
534
535    /**
536     * Returns the parent of the reflected class or <b>false</b> when no parent
537     * exists.
538     *
539     * @return \ReflectionClass|boolean
540     */
541    public function getParentClass()
542    {
543        return false;
544    }
545
546    /**
547     * Returns the constructor of the reflected interface, what means <b>null</b>
548     * because an interface has no constructor.
549     *
550     * @return \ReflectionClass
551     */
552    public function getConstructor()
553    {
554        return null;
555    }
556
557    /**
558     * Checks whether a specific method is defined in a class.
559     *
560     * @param string $name Name of the method being checked for.
561     *
562     * @return boolean
563     */
564    public function hasMethod( $name )
565    {
566        return isset( $this->_methods[strtolower( $name )] ) || $this->_hasMethod( $name );
567    }
568
569    /**
570     * Checks whether a specific method is defined in one of the parent interfaces.
571     *
572     * @param string $name Name of the method being checked for.
573     *
574     * @return boolean
575     */
576    private function _hasMethod( $name )
577    {
578        foreach ( $this->getInterfaces() as $interface )
579        {
580            if ( $interface->hasMethod( $name ) )
581            {
582                return true;
583            }
584        }
585        return false;
586    }
587
588    /**
589     * Gets a <b>ReflectionMethod</b> about a method.
590     *
591     * @param string $name The method name to reflect.
592     *
593     * @return \ReflectionMethod
594     * @throws \ReflectionException When no methods exists for the given name.
595     */
596    public function getMethod( $name )
597    {
598        if ( isset( $this->_methods[strtolower( $name )] ) )
599        {
600            return $this->_methods[strtolower( $name )];
601        }
602        return $this->_getMethodFromParentInterfaces( $name );
603    }
604
605    /**
606     * Gets a <b>ReflectionMethod</b> about a method from one of the parent
607     * interfaces.
608     *
609     * @param string $name The method name to reflect.
610     *
611     * @return \ReflectionMethod
612     */
613    private function _getMethodFromParentInterfaces( $name )
614    {
615        foreach ( $this->getInterfaces() as $interface )
616        {
617            if ( $interface->hasMethod( $name ) )
618            {
619                return $interface->getMethod( $name );
620            }
621        }
622        throw new \ReflectionException( sprintf( 'Method %s does not exist', $name ) );
623    }
624
625    /**
626     * Returns an array with all methods within the inheritence hierarchy of this
627     * class or interface.
628     *
629     * @param integer $filter Optional bitfield describing the modifiers a returned
630     *        method must have.
631     *
632     * @return array(\ReflectionMethod)
633     */
634    public function getMethods( $filter = -1 )
635    {
636        return $this->prepareCollectedObjects( $filter, $this->collectMethods() );
637    }
638
639    /**
640     * Returns an array with all methods declared in the inheritence hierarchy
641     * of the current interface.
642     *
643     * @return array(\ReflectionMethod)
644     */
645    protected function collectMethods()
646    {
647        $result = $this->_collectMethods( (array) $this->_methods );
648        foreach ( $this->getInterfaces() as $interface )
649        {
650            $result = $this->_collectMethods( $interface->getMethods(), $result );
651        }
652        return $result;
653    }
654
655    /**
656     * Collects all methods from <b>$methods</b> and adds those methods to the
657     * <b>&$result</b> that do not already exist in this array,
658     *
659     * @param array(string=>\ReflectionMethod) $methods Input methods.
660     * @param array(string=>\ReflectionMethod) $result  Resulting method array.
661     *
662     * @return array(string=>\ReflectionMethod)
663     */
664    private function _collectMethods( array $methods, array $result = array() )
665    {
666        foreach ( $methods as $method )
667        {
668            $result = $this->_collectMethod( $method, $result );
669        }
670        return $result;
671    }
672
673    /**
674     * Adds the given method <b>$method</b> to <b>&$result</b> when a method
675     * with same name does not exist in this array,
676     *
677     * @param \ReflectionMethod                $method Input method.
678     * @param array(string=>\ReflectionMethod) $result Resulting method array.
679     *
680     * @return array(string=>\ReflectionMethod)
681     */
682    private function _collectMethod( \ReflectionMethod $method, array $result )
683    {
684        $name = strtolower( $method->getName() );
685        if ( !isset( $result[$name] ) )
686        {
687            $result[$name] = $method;
688        }
689        return $result;
690    }
691
692    /**
693     * Prepares the given array and returns a filtered version of the given
694     * object list.
695     *
696     * @param integer        $filter  Bitfield with required object modifiers.
697     * @param array(objects) $objects List of ast objects.
698     *
699     * @return array(objects)
700     */
701    protected function prepareCollectedObjects( $filter, array $objects )
702    {
703        if ( $filter === -1 )
704        {
705            return array_values( $objects );
706        }
707        return $this->_filterCollectedObjects( $filter, $objects );
708    }
709
710    /**
711     * Filters the given array against the given filter bitfield.
712     *
713     * @param integer        $filter  Bitfield with required object modifiers.
714     * @param array(objects) $objects List of ast objects.
715     *
716     * @return array(objects)
717     */
718    private function _filterCollectedObjects( $filter, array $objects )
719    {
720        $result = array();
721        foreach ( $objects as $object )
722        {
723            if ( ( $object->getModifiers() & $filter ) === $filter )
724            {
725                $result[] = $object;
726            }
727        }
728        return $result;
729    }
730
731    /**
732     * This method initializes the methods that are declared for the reflected
733     * class or interface.
734     *
735     * @param array(\ReflectionMethod) $methods The declared class/interface methods.
736     *
737     * @return void
738     * @access private
739     */
740    public function initMethods( array $methods )
741    {
742        if ( $this->_methods === null )
743        {
744            $this->_methods = array();
745            foreach ( $methods as $method )
746            {
747                $method->initDeclaringClass( $this );
748                $this->_methods[strtolower( $method->getName() )] = $method;
749            }
750        }
751        else
752        {
753            throw new \LogicException( 'Methods already set' );
754        }
755    }
756
757    /**
758     * Checks whether the specified property is defined.
759     *
760     * @param string $name Name of the property being checked for.
761     *
762     * @return boolean
763     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
764     */
765    public function hasProperty( $name )
766    {
767        return false;
768    }
769
770    /**
771     * Gets a property.
772     *
773     * @param string $name The property name.
774     *
775     * @return \ReflectionProperty
776     */
777    public function getProperty( $name )
778    {
779        throw new \ReflectionException( sprintf( 'Property %s does not exist', $name ) );
780    }
781
782    /**
783     * Returns an array with all properties declared/defined in this interface.
784     * This value will always be an empty array.
785     *
786     * @param integer $filter Optional bitfield describing the modifiers a returned
787     *        property must have.
788     *
789     * @return array(\ReflectionProperty)
790     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
791     */
792    public function getProperties( $filter = -1 )
793    {
794        return array();
795    }
796
797    /**
798     * Gets default properties from a class.
799     *
800     * @return array(mixed)
801     */
802    public function getDefaultProperties()
803    {
804        return array();
805    }
806
807    /**
808     * Gets the static property values.
809     *
810     * @param string $name    The property name.
811     * @param mixed  $default Optional default value.
812     *
813     * @return mixed
814     */
815    public function getStaticPropertyValue( $name, $default = null )
816    {
817        if ( $default === null )
818        {
819            throw new \ReflectionException(
820                sprintf( 'Class %s does not have a property named %s', $this->_name, $name )
821            );
822        }
823        return $default;
824    }
825
826    /**
827     * Get the static properties.
828     *
829     * @return array(string=>mixed)
830     */
831    public function getStaticProperties()
832    {
833        return array();
834    }
835
836    /**
837     * Sets static property value.
838     *
839     * @param string $name  The property name.
840     * @param mixed  $value The new property value.
841     *
842     * @return void
843     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
844     */
845    public function setStaticPropertyValue( $name, $value )
846    {
847        throw new \ReflectionException( 'Method setStaticPropertyValue() is not supported' );
848    }
849
850    /**
851     * Get the starting line number.
852     *
853     * @return integer
854     */
855    public function getStartLine()
856    {
857        return $this->_startLine;
858    }
859
860    /**
861     * Initializes the start line number. Note that this method is only used
862     * internally by this component.
863     *
864     * @param integer $startLine Line number where the interface declaration starts.
865     *
866     * @return void
867     * @access private
868     */
869    public function initStartLine( $startLine )
870    {
871        if ( $this->_startLine === -1 )
872        {
873            $this->_startLine = $startLine;
874        }
875        else
876        {
877            throw new \LogicException( 'Property startLine already set.' );
878        }
879    }
880
881    /**
882     * Get the ending line number.
883     *
884     * @return integer
885     */
886    public function getEndLine()
887    {
888        return $this->_endLine;
889    }
890
891    /**
892     * Initializes the end line number. Note that this method is only used
893     * internally by this component.
894     *
895     * @param integer $endLine Line number where the interface declaration ends.
896     *
897     * @return void
898     * @access private
899     */
900    public function initEndLine( $endLine )
901    {
902        if ( $this->_endLine === -1 )
903        {
904            $this->_endLine = $endLine;
905        }
906        else
907        {
908            throw new \LogicException( 'Property endLine already set.' );
909        }
910    }
911
912    /**
913     * Gets an extensions <b>\ReflectionExtension</b> object or <b>null</b>.
914     *
915     * @return \ReflectionExtension
916     */
917    public function getExtension()
918    {
919        return null;
920    }
921
922    /**
923     * Returns the name of the owning extension or <b>false</b>.
924     *
925     * @return string|boolean
926     */
927    public function getExtensionName()
928    {
929        return false;
930    }
931
932    /**
933     * Creates an instance of the context class.
934     *
935     * @param mixed $args Accepts a variable number of arguments which are
936     *                    passed to the function much like call_user_func().
937     *
938     * @return object
939     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
940     */
941    public function newInstance( $args )
942    {
943        throw new \ReflectionException( 'Method newInstance() is not supported' );
944    }
945
946    /**
947     * Creates an instance of the context class.
948     *
949     * @param array(mixed) $args Arguments which are passed to the constructor
950     *                           much like call_user_func_array().
951     *
952     * @return object
953     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
954     */
955    public function newInstanceArgs( array $args = array() )
956    {
957        throw new \ReflectionException( 'Method newInstanceArgs() is not supported' );
958    }
959
960    /**
961     * Returns a string representation of this reflection instance.
962     *
963     * @return string
964     */
965    public function __toString()
966    {
967        return sprintf(
968            'Interface [ <user> interface %s%s ] %s',
969            $this->getShortName(),
970            $this->implementedInterfacesToString(),
971            $this->bodyToString()
972        );
973    }
974
975    /**
976     * This method returns a string representation of the parent interfaces or
977     * an empty string when the reflected interface does not declare any parents.
978     *
979     * @return string
980     */
981    protected function implementedInterfacesToString()
982    {
983        if ( count( $this->getInterfaceNames() ) === 0 )
984        {
985            return '';
986        }
987        return ' extends ' . join( ', ', $this->getInterfaceNames() );
988    }
989
990    /**
991     * This method creates a string representation of all defined constants,
992     * methods and properties on the currently reflected class or interface.
993     *
994     * @return string
995     */
996    protected function bodyToString()
997    {
998        return sprintf(
999            '{' . PHP_EOL .
1000            '  @@ %s %d-%d' . PHP_EOL . PHP_EOL .
1001            '  - Constants [%d] {' . PHP_EOL .
1002            '%s  }' . PHP_EOL . PHP_EOL .
1003            '  - Properties [%d] {' . PHP_EOL .
1004            '%s  }' . PHP_EOL . PHP_EOL .
1005            '  - Methods [%d] {' . PHP_EOL .
1006            '%s  }' . PHP_EOL .
1007            '}',
1008            $this->getFileName(),
1009            $this->getStartLine(),
1010            $this->getEndLine(),
1011            count( $this->getConstants() ),
1012            $this->constantsToString(),
1013            count( $this->getProperties() ),
1014            $this->propertiesToString(),
1015            count( $this->getMethods() ),
1016            $this->methodsToString()
1017        );
1018    }
1019
1020    /**
1021     * This method returns a string representation of all constants defined
1022     * for the currently reflected interface.
1023     *
1024     * @return string
1025     */
1026    protected function constantsToString()
1027    {
1028        $string = '';
1029        foreach ( $this->getConstants() as $name => $value )
1030        {
1031            $string .= sprintf(
1032                '    Constant [ %s %s ] { %s }%s',
1033                gettype( $value ),
1034                $name,
1035                is_bool( $value ) ? ( $value ? 'true' : 'false' ) : $value,
1036                PHP_EOL
1037            );
1038        }
1039        return $string;
1040    }
1041
1042    /**
1043     * This method returns a string representation of all properties declared
1044     * for the currently reflected interface.
1045     *
1046     * @return string
1047     */
1048    protected function propertiesToString()
1049    {
1050        return '';
1051    }
1052
1053    /**
1054     * This method returns a string representation of all methods declared
1055     * for the currently reflected interface.
1056     *
1057     * @return string
1058     */
1059    protected function methodsToString()
1060    {
1061        $string = '';
1062        foreach ( $this->getMethods() as $method )
1063        {
1064            $string .= $method->__toString( '    ' ) . PHP_EOL;
1065        }
1066        return $string;
1067    }
1068}
1069