Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * Intermediate class parsing structure.
4
 *
5
 * phpDocumentor :: automatic documentation generator
6
 *
7
 * PHP versions 4 and 5
8
 *
9
 * Copyright (c) 2001-2007 Gregory Beaver
10
 *
11
 * LICENSE:
12
 *
13
 * This library is free software; you can redistribute it
14
 * and/or modify it under the terms of the GNU Lesser General
15
 * Public License as published by the Free Software Foundation;
16
 * either version 2.1 of the License, or (at your option) any
17
 * later version.
18
 *
19
 * This library is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22
 * Lesser General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Lesser General Public
25
 * License along with this library; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
 *
28
 * @category  ToolsAndUtilities
29
 * @package   phpDocumentor
30
 * @author    Greg Beaver <cellog@php.net>
31
 * @copyright 2001-2007 Gregory Beaver
32
 * @license   http://www.opensource.org/licenses/lgpl-license.php LGPL
33
 * @version   CVS: $Id: Classes.inc 243933 2007-10-10 01:18:25Z ashnazg $
34
 * @filesource
35
 * @link      http://www.phpdoc.org
36
 * @link      http://pear.php.net/PhpDocumentor
37
 * @see       parserDocBlock, parserInclude, parserPage, parserClass
38
 * @see       parserDefine, parserFunction, parserMethod, parserVar
39
 * @since     1.0rc1
40
 * @todo      CS cleanup - change package to PhpDocumentor
41
 */
42
/**
43
 * Intermediate class parsing structure.
44
 *
45
 * The {@link phpDocumentor_IntermediateParser} class uses this class and its
46
 * cousin, {@link ProceduralPages} to organize all parsed source code elements.
47
 * Data is fed to each immediately after it is parsed, and at conversion time,
48
 * everything is organized.
49
 *
50
 * The Classes class is responsible for all inheritance, including resolving
51
 * name conflicts between classes, determining which classes extend other
52
 * classes, and is responsible for all inheritance of documentation.
53
 * {@internal
54
 * This structure parses classes, vars and methods by file, and then iterates
55
 * over the class tree to set up inheritance.  The {@link Inherit()}
56
 * method is the meat of the class, and processes the class trees from root to
57
 * branch, ensuring that parsing order is unimportant.}}
58
 *
59
 * @category  ToolsAndUtilities
60
 * @package   phpDocumentor
61
 * @author    Greg Beaver <cellog@php.net>
62
 * @copyright 2001-2007 Gregory Beaver
63
 * @license   http://www.opensource.org/licenses/lgpl-license.php LGPL
64
 * @version   Release: 1.4.3
65
 * @link      http://www.phpdoc.org
66
 * @link      http://pear.php.net/PhpDocumentor
67
 * @since     1.0rc1
68
 * @todo      CS cleanup - change package to PhpDocumentor
69
 */
70
class Classes
71
{
72
    /**#@+
73
     * @access private
74
     */
75
    /**
76
     * file being parsed, used in every add function to match up elements with
77
     * the file that contains them
78
     *
79
     * This variable is used during parsing to associate class elements added
80
     * to the data structures that contain them with the file they reside in
81
     * @see addClass(), addMethod(), addVar(), nextFile()
82
     * @var string
83
     */
84
    var $curfile;
85
    /**
86
     * class being parsed, used to match up methods and vars with their parent
87
     * class
88
     *
89
     * This variable is used during parsing to associate class elements added
90
     * to the data structures that contain them with the file they reside in
91
     * @see addMethod(), addVar()
92
     * @var string
93
     */
94
    var $curclass;
95
 
96
    /**
97
     * Used when a definite match is made between a parent class and a child
98
     * class
99
     *
100
     * This variable is used in post-parsing.
101
     *
102
     * Format:<pre>
103
     * array(
104
     *     parent => array(
105
     *         parentfile => array(
106
     *             child => childfile
107
     *         )
108
     *     )
109
     * )</pre>
110
     * @var array
111
     */
112
    var $definitechild;
113
    /**
114
     * array of parsed classes organized by the name of the file that contains
115
     * the class.
116
     *
117
     * Format:<pre>
118
     * array(
119
     *     filename => array(
120
     *         classname => {@link parserClass}
121
     *     )
122
     * )</pre>
123
     * @var array
124
     */
125
    var $classesbyfile = array();
126
    /**
127
     * array of file names organized by classes that are in the file.
128
     *
129
     * This structure is designed to handle name conflicts.  Two files can
130
     * contain classes with the same name, and this array will record both
131
     * filenames to help control linking and inheritance errors
132
     *
133
     * Format:<pre>
134
     * array(
135
     *     classname => array(
136
     *         name of file containing classname,
137
     *         name of file 2 containing classname,
138
     *         ...
139
     *     )
140
     * )</pre>
141
     * @var array
142
     */
143
    var $classesbynamefile = array();
144
    /**
145
     * array of parsed methods organized by the file that contains them.
146
     *
147
     * Format:<pre>
148
     * array(
149
     *     filename => array(
150
     *         classname => array(
151
     *             {@link parserMethod} 1,
152
     *             {@link parserMethod} 2,
153
     *             ...
154
     *         )
155
     *     )
156
     * )</pre>
157
     * @var array
158
     */
159
    var $methodsbyfile = array();
160
    /**
161
     * array of parsed vars organized by the file that contains them.
162
     *
163
     * Format:<pre>
164
     * array(
165
     *     filename => array(
166
     *         classname => array(
167
     *             {@link parserVar} 1,
168
     *             {@link parserVar} 2,
169
     *             ...
170
     *         )
171
     *     )
172
     * )</pre>
173
     * @var array
174
     */
175
    var $varsbyfile = array();
176
    /**
177
     * array of parsed class constants organized by the file that contains them.
178
     *
179
     * Format:<pre>
180
     * array(
181
     *     filename => array(
182
     *         classname => array(
183
     *             {@link parserConst} 1,
184
     *             {@link parserConst} 2,
185
     *             ...
186
     *         )
187
     *     )
188
     * )</pre>
189
     * @var array
190
     */
191
    var $constsbyfile = array();
192
    /**
193
     * keeps track of extend declarations by file, used to find inheritance
194
     *
195
     * Format:<pre>
196
     * array(
197
     *     filename => array(
198
     *         classname => parentclassname
199
     *     )
200
     * )</pre>
201
     * @var array
202
     */
203
    var $extendsbyfile = array();
204
    /**
205
     * Keeps track of child classes by file.
206
     * Since phpDocumentor can document collections of files that contain name
207
     * conflicts (PHP would give a fatal error), it
208
     * is impossible to assume a class that declares "extends foo" necessarily
209
     * extends the class foo in file X.  It could be an
210
     * extended class of class foo in file Y.  Because of this, phpDocumentor
211
     * relies on packaging to resolve the name conflict
212
     * This array keeps track of the packages of a child class
213
     *
214
     * Format:<pre>
215
     * array(
216
     *     parentclassname => array(
217
     *         filename => array(
218
     *             childclassname => array(
219
     *                 packagename,
220
     *                 packagename
221
     *             )
222
     *         )
223
     *     )
224
     * )</pre>
225
     * @var array
226
     */
227
    var $classchildrenbyfile = array();
228
    /**
229
     * Keeps track of class packages found in a file.
230
     * This is used in {@link getParentClass()} to determine the number of
231
     * packages in a file, in order to resolve inheritance issues
232
     * Format:<pre>
233
     * array(
234
     *     filename => array(
235
     *         packagename1,
236
     *         packagename2,
237
     *         ...
238
     *     )
239
     * )</pre>
240
     * @var array
241
     */
242
    var $classpackagebyfile = array();
243
    /**
244
     * a tree of class inheritance by name.
245
     *
246
     * Format:<pre>
247
     * array(
248
     *     childname => parentname,
249
     *     childname1 => parentname1,
250
     *     rootname => 0,
251
     *     ...
252
     * )</pre>
253
     * @var array
254
     * @see Converter::generateSortedClassTreeFromClass()
255
     */
256
    var $classparents = array();
257
    /**
258
     * Keeps track of package and subpackage for each class name, organized
259
     * by package
260
     *
261
     * Format:<pre>
262
     * array(
263
     *     classname => array(
264
     *         path => array(
265
     *             package,
266
     *             subpackage
267
     *         ),
268
     *         path2 => array(
269
     *             package,
270
     *             subpackage
271
     *         ),
272
     *         ...
273
     *     )
274
     * )</pre>
275
     * @var array
276
     */
277
    var $classpathpackages = array();
278
    /**
279
     * used to delete duplicates in the same package to avoid documentation errors
280
     *
281
     * Specifically used in {@link Converter::checkKillClass()}
282
     */
283
    var $killclass = array();
284
    /**
285
     * array of methods by package and class
286
     *
287
     * format:<pre>
288
     * array(packagename =>
289
     *         array(classname =>
290
     *               array(methodname1 => {@link parserMethod} class,
291
     *                     methodname2 => {@link parserMethod} class,...)
292
     *                      )
293
     *              )
294
     *      )</pre>
295
     * @var array
296
     * @see Converter
297
     */
298
    var $methods = array();
299
 
300
    /**
301
     * array of class variables by package and class
302
     *
303
     * format:<pre>
304
     * array(packagename =>
305
     *         array(classname =>
306
     *                array(variablename1 => {@link parserVar} class,
307
     *                      variablename2 => {@link parserVar} class,...
308
     *                     )
309
     *              )
310
     *      )</pre>
311
     * @var array
312
     * @see Converter
313
     */
314
    var $vars = array();
315
 
316
    /**
317
     * array of class variables by package and class
318
     *
319
     * format:<pre>
320
     * array(packagename =>
321
     *         array(classname =>
322
     *                array(constname1 => {@link parserConst} class,
323
     *                      constname2 => {@link parserConst} class,...
324
     *                     )
325
     *              )
326
     *      )</pre>
327
     * @var array
328
     * @see Converter
329
     */
330
    var $consts = array();
331
    /**
332
     * Reverse class_packages_by_file, used to prevent duplicates
333
     * @var array Format: array(packagename => 1)
334
     */
335
    var $revcpbf = array();
336
    /**
337
     * All classes with no parents (no extends clause) are tracked in this array
338
     * by the file that contains them.
339
     *
340
     * Format:<pre>
341
     * array(
342
     *     classname => array(
343
     *         name of file1 that contains root classname,
344
     *         name of file2 that contains root classname,
345
     *         ...
346
     *     )
347
     * )</pre>
348
     * @var array
349
     */
350
    var $roots = array();
351
    /**
352
     * All classes with a parent that was not parsed are included in this array
353
     *
354
     * Format:<pre>
355
     * array(
356
     *     classname => array(
357
     *         name of file1 that contains root classname,
358
     *         name of file2 that contains root classname,
359
     *         ...
360
     *     )
361
     * )</pre>
362
     * @var array
363
     */
364
    var $specialRoots = array();
365
 
366
    /**
367
     * array of all files that contain classes with the same name
368
     * @var array Format: (classname => array(path1, path2,...))
369
     */
370
    var $potentialclassconflicts = array();
371
 
372
    /**
373
     * array of all inter-package name conflicts of classes
374
     *
375
     * This array allows documentation of PHP namespace conflicts that would
376
     * occur should a user try to include these files in the same file
377
     * @var array Format: (classname => array(path1, path2,...))
378
     */
379
    var $classconflicts = array();
380
    /**#@-*/
381
    /**
382
     * While parsing, add a class to the list of parsed classes
383
     *
384
     * sets up the {@link $classesbyfile, $classesbynamefile, $extendsbyfile},
385
     * {@link $classchildrenbyfile, $roots} arrays, and sets {@link $curclass}
386
     *
387
     * @param parserClass &$element element is a {@link parserClass}
388
     *
389
     * @return void
390
     * @uses addPackageToFile() marks the current class's package as being
391
     *                          present in a file
392
     */
393
    function addClass(&$element)
394
    {
395
        $this->curclass   = $element->getName();
396
        $element->curfile = $this->curfile;
397
        if (isset($this->classesbyfile[$this->curfile][$this->curclass])) {
398
            addWarning(PDERROR_ELEMENT_IGNORED,
399
                'class', $this->curclass, $this->curfile);
400
            $this->curclass = false;
401
            return;
402
        }
403
        $this->
404
            classesbyfile
405
                [$this->curfile][$this->curclass]
406
            = $element;
407
        $this->
408
            classesbynamefile[$this->curclass][]
409
            = $this->curfile;
410
        $this->
411
            extendsbyfile[$this->curfile][$this->curclass]
412
            = $element->getExtends();
413
        $this->
414
            classchildrenbyfile[$element->getExtends()]
415
                [$this->curfile][$this->curclass][]
416
            = $element->docblock->package;
417
        if ($element->docblock->getExplicitPackage())
418
        $this->addPackageToFile($element->docblock->package);
419
        if (!$element->getExtends()) {
420
            $this->roots[$this->curclass][] = $this->curfile;
421
        }
422
    }
423
 
424
    /**
425
     * While parsing, add a method to the list of parsed methods
426
     *
427
     * sets up the {@link $methodsbyfile} array using {@link $curfile} and
428
     * {@link $curclass}
429
     *
430
     * @param parserMethod &$element element is a {@link parserMethod}
431
     *
432
     * @return void
433
     */
434
    function addMethod(&$element)
435
    {
436
        if (!$this->curclass) return;
437
        $this->methodsbyfile[$this->curfile][$this->curclass][] = $element;
438
    }
439
 
440
    /**
441
     * While parsing, add a variable to the list of parsed variables
442
     *
443
     * sets up the {@link $varsbyfile} array using {@link $curfile}
444
     * and {@link $curclass}
445
     *
446
     * @param parserVar &$element element is a {@link parserVar}
447
     *
448
     * @return void
449
     */
450
    function addVar(&$element)
451
    {
452
        if (!$this->curclass) return;
453
        $this->varsbyfile[$this->curfile][$this->curclass][] = $element;
454
    }
455
 
456
    /**
457
     * While parsing, add a variable to the list of parsed variables
458
     *
459
     * sets up the {@link $constsbyfile} array using {@link $curfile}
460
     * and {@link $curclass}
461
     *
462
     * @param parserConst &$element element is a {@link parserConst}
463
     *
464
     * @return void
465
     */
466
    function addConst(&$element)
467
    {
468
        if (!$this->curclass) return;
469
        $this->constsbyfile[$this->curfile][$this->curclass][] = $element;
470
    }
471
 
472
    /**
473
     * Prepare to parse a new file
474
     *
475
     * sets {@link $curfile} to $file and {@link $curclass}
476
     * to false (no class being parsed)
477
     *
478
     * @param string $file file currently being parsed
479
     *
480
     * @return void
481
     */
482
    function nextFile($file)
483
    {
484
        $this->curfile  = $file;
485
        $this->curclass = false;
486
    }
487
 
488
    /**
489
     * Mark a package as being used in a class
490
     *
491
     * {@source}
492
     *
493
     * @param string $package package name
494
     *
495
     * @return void
496
     */
497
    function addPackageToFile($package)
498
    {
499
        if (!isset($this->revcpbf[$this->curfile][$package]))
500
        $this->classpackagebyfile[$this->curfile][] = $package;
501
        $this->revcpbf[$this->curfile][$package]    = 1;
502
    }
503
 
504
    /**
505
     * Find the parent class of $class, and set up structures to note this fact
506
     *
507
     * Modifies the {@link parserClass} element in {@link $classesbyfile} to use
508
     * the parent's package, and inherit methods/vars
509
     *
510
     * @param string $class child class to find parent class
511
     * @param string $file  file child class is located in
512
     *
513
     * @return void
514
     * @uses $definitechild if a match is made between a parent class and parameter
515
     *                      $class in file $file, then definitechild is set here
516
     * @uses getParentClass() to find the parent class
517
     */
518
    function setClassParent($class,$file)
519
    {
520
        if (is_array($par = $this->getParentClass($class, $file))) {
521
            // (for debugging)
522
            // phpDocumentor_out("$file class $class extends "
523
            //    . $par[1] ." file ". $par[0] . "\n");
524
 
525
            $this->classesbyfile[$file][$class]->setParent($par[1], $par[0], $this);
526
            $this->definitechild[$par[1]][$par[0]][$class] = $file;
527
        } else {
528
            $this->classesbyfile[$file][$class]->setParentNoClass($par);
529
        }
530
    }
531
 
532
    /**
533
     * Main processing engine for setting up class inheritance.
534
     *
535
     * This function uses {@link $roots} to traverse the inheritance tree via
536
     * {@link processChild()} and returns the data structures
537
     * phpDocumentor_IntermediateParser needs to convert parsed data
538
     * to output using {@link phpDocumentor_IntermediateParser::Convert()}
539
     *
540
     * @param phpDocumentor_IntermediateParser &$render the renderer object
541
     *
542
     * @return void
543
     * @uses processChild() set up inheritance
544
     * @todo CS Cleanup - rename to "inherit" for CamelCaps naming standard
545
     */
546
    function Inherit(&$render)
547
    {
548
        phpDocumentor_out("\nProcessing Class Inheritance\n\n");
549
        flush();
550
        phpDocumentor_out("\nProcessing Root Trees\n\n");
551
        flush();
552
        foreach ($this->roots as $class => $files) {
553
            for ($i=0; $i<count($files); $i++) {
554
                $this->processChild($render, $class, $files[$i]);
555
            }
556
        }
557
        if (0)
558
        foreach ($this->classesbyfile as $i => $j) {
559
            foreach ($j as $k => $m) {
560
                var_dump($i, $k);
561
                if ($i == 'iConverter') {
562
                    var_dump($j);
563
                }
564
            }
565
        }
566
        phpDocumentor_out("\nProcessing leftover classes "
567
            . "(classes that extend root classes not found in the same package)\n");
568
        flush();
569
        foreach ($this->classesbyfile as $i => $j) {
570
            foreach ($j as $k => $m) {
571
                $this->processChild($render, $k, $i, true);
572
            }
573
        }
574
        phpDocumentor_out("done processing leftover classes\n");
575
        flush();
576
        $this->setupClassConflicts();
577
    }
578
 
579
    /**
580
     * Transfers actual conflicts from {@link $potentialClassconflicts} to
581
     * {@link $classconflicts}
582
     *
583
     * @return void
584
     * @access private
585
     * @uses $potentialclassconflicts transfers values to {@link $classconflicts}
586
     */
587
    function setupClassConflicts()
588
    {
589
        foreach ($this->potentialclassconflicts as $class => $paths) {
590
            if (count($paths) - 1) { //conflict
591
                $package = array();
592
                foreach ($paths as $path) {
593
                    // create a list of conflicting classes in each package
594
                    if (isset($this->classpathpackages[$class][$path]))
595
                    $package[$this->classpathpackages[$class][$path][0]][] = $path;
596
                }
597
                foreach ($package as $pathpackages) {
598
                    /*
599
                     * if at least 2 functions exist in the same package,
600
                     * delete all but the first one and add warnings
601
                     */
602
                    if (count($pathpackages) - 1) {
603
                        for ($i=1; $i < count($pathpackages); $i++) {
604
                            if (isset($this->classesbyfile[$pathpackages[$i]])) {
605
                                addWarning(PDERROR_ELEMENT_IGNORED,
606
                                    'class', $class, $pathpackages[$i]);
607
                                $this->killClass($class, $pathpackages[$i]);
608
                                $oth = array_flip($paths);
609
                                unset($paths[$oth[$pathpackages[$i]]]);
610
                            }
611
                        }
612
                    }
613
                }
614
                $this->classconflicts[$class] = $paths;
615
            }
616
        }
617
    }
618
 
619
    /**
620
     * If a package contains two classes with the same name, this function finds
621
     * that conflict
622
     *
623
     * Returns the {@link $classconflicts} entry for class $class, minus its own path
624
     *
625
     * @param mixed $class the class name to search for
626
     *
627
     * @return mixed returns false if no conflicts,
628
     *               or an array of paths containing conflicts
629
     */
630
    function getConflicts($class)
631
    {
632
        if (!isset($this->classconflicts[$class])) return false;
633
        $a = array();
634
        foreach ($this->classconflicts[$class] as $conflict) {
635
            $a[$this->classesbyfile[$conflict][$class]->docblock->package]
636
                = $this->classesbyfile[$conflict][$class];
637
        }
638
        return $a;
639
    }
640
 
641
    /**
642
     * sets up {@link $killclass} for use by Converter::checkKillClass()
643
     *
644
     * @param mixed $class the class
645
     * @param mixed $path  the path
646
     *
647
     * @return void
648
     * @access private
649
     */
650
    function killClass($class,$path)
651
    {
652
        $this->killclass[$class][$path] = true;
653
    }
654
 
655
    /**
656
     * This function recursively climbs up the class tree, setting inherited
657
     * information like package and adds the elements to
658
     * {@link phpDocumentor_IntermediateParser}.
659
     *
660
     * Using structures defined in {@link Classes},
661
     * the function first sets package information,
662
     * and then seeks out child classes.
663
     * It uses 3 tests to determine whether a class is a child class.
664
     * <ol>
665
     *    <li>child class is in the same file as the parent class
666
     *        and extends parent class
667
     *    </li>
668
     *    <li>child class is in a different file and specifies
669
     *        the parent's @package in its docblock
670
     *    </li>
671
     *    <li>child class is in a different file and is in a
672
     *        different @package, with one possible parent class
673
     *    </li>
674
     * </ol>
675
     *
676
     * @param phpDocumentor_IntermediateParser &$render the renderer object
677
     * @param string                           $class   class to process
678
     * @param string                           $file    name of file $class
679
     *                                                  is located in
680
     * @param boolean                          $furb    flag used privately
681
     *                                                  to control informational
682
     *                                                  output while parsing
683
     *                                                  (used when processing
684
     *                                                  leftover classes in
685
     *                                                  {@link Inherit()}
686
     *
687
     * @return void
688
     * @global string default package, usually "default"
689
     */
690
    function processChild(&$render,$class,$file,$furb = false)
691
    {
692
        global $phpDocumentor_DefaultPackageName;
693
        if (isset($this->classesbyfile[$file][$class]->processed))
694
            return;
695
        $this->potentialclassconflicts[$class][] = $file;
696
        if ($furb)
697
            phpDocumentor_out("Processing $class in file $file\n");
698
        flush();
699
        $this->classesbyfile[$file][$class]->processed = true;
700
 
701
        $db = $this->classesbyfile[$file][$class];
702
        $render->addUses($db, $file);
703
        if (!$render->parsePrivate) {
704
            /*
705
             * if this class has an @access private,
706
             * and parse private is disabled, remove it
707
             */
708
            if ($db->docblock->hasaccess) {
709
                $aaa = $db->docblock->getKeyword('access');
710
                if (is_object($aaa) && $aaa->getString() == 'private') {
711
                    if (isset($this->varsbyfile[$file])
712
                        && isset($this->varsbyfile[$file][$class])) {
713
                        unset($this->varsbyfile[$file][$class]);
714
                    }
715
                    if (isset($this->methodsbyfile[$file])
716
                        && isset($this->methodsbyfile[$file][$class])) {
717
                        unset($this->methodsbyfile[$file][$class]);
718
                    }
719
                    if (isset($this->constsbyfile[$file])
720
                        && isset($this->constsbyfile[$file][$class])) {
721
                        unset($this->constsbyfile[$file][$class]);
722
                    }
723
                    $this->classesbyfile[$file][$class]->ignore = true;
724
                    // if this is a root class, remove it from the roots array
725
                    if (isset($this->roots[$class])) {
726
                        foreach ($this->roots[$class] as $i => $files) {
727
                            // find the file key and unset
728
                            if ($files == $file)
729
                                unset($this->roots[$class][$i]);
730
                        }
731
                    }
732
                    /*
733
                     * if this is a child, remove it from the list
734
                     * of child classes of its parent
735
                     */
736
                    if ($db->getExtends())
737
                        unset($this->classchildrenbyfile[$db->getExtends()][$file]);
738
                    return;
739
                }
740
            }
741
        }
742
        if ($render->packageoutput) {
743
            if (!in_array($db->docblock->package, $render->packageoutput)) {
744
                if (isset($this->varsbyfile[$file])
745
                    && isset($this->varsbyfile[$file][$class])) {
746
                    unset($this->varsbyfile[$file][$class]);
747
                }
748
                if (isset($this->methodsbyfile[$file])
749
                    && isset($this->methodsbyfile[$file][$class])) {
750
                    unset($this->methodsbyfile[$file][$class]);
751
                }
752
                if (isset($this->constsbyfile[$file])
753
                    && isset($this->constsbyfile[$file][$class])) {
754
                    unset($this->constsbyfile[$file][$class]);
755
                }
756
                $this->classesbyfile[$file][$class]->ignore = true;
757
                if (isset($this->roots[$class])) {
758
                    foreach ($this->roots[$class] as $i => $files) {
759
                        if ($files == $file) unset($this->roots[$class][$i]);
760
                    }
761
                }
762
                if ($db->getExtends())
763
                    unset($this->classchildrenbyfile[$db->getExtends()][$file]);
764
                return;
765
            }
766
        }
767
        $this->setClassParent($class, $file);
768
        $db = $this->classesbyfile[$file][$class];
769
        if ($furb && !is_array($db->parent)) {
770
            // debug("furb adding $class $file to roots");
771
            $this->specialRoots[$db->parent][] = array($class, $file);
772
        }
773
        // fix for 591396
774
        if (!$db->docblock->getExplicitPackage()) {
775
            $a = $render->proceduralpages->pagepackages[$file];
776
            if ($a[0] != $phpDocumentor_DefaultPackageName) {
777
                // inherit page package
778
                $this->classesbyfile[$file][$class]->docblock->package = $a[0];
779
            }
780
        }
781
        if ($this->classesbyfile[$file][$class]->docblock->package
782
            == $render->proceduralpages->pagepackages[$file][0]) {
783
            if ($this->classesbyfile[$file][$class]->docblock->subpackage == '') {
784
                $this->classesbyfile[$file][$class]->docblock->subpackage
785
                    = $render->proceduralpages->pagepackages[$file][1];
786
            }
787
        }
788
        $db = $this->classesbyfile[$file][$class];
789
        $render->addPackageParent($db);
790
        $render->addPageIfNecessary($file, $db);
791
        if ($access = $db->docblock->getKeyword('access')) {
792
            if (!is_string($access) && is_object($access))
793
                $access = $access->getString();
794
            if (!is_string($access))
795
                $access = 'public';
796
            if (($access == 'private') && (!$render->parsePrivate)) {
797
                if (isset($this->varsbyfile[$file])
798
                    && isset($this->varsbyfile[$file][$class])) {
799
                    foreach ($this->varsbyfile[$file][$class] as $i => $vr) {
800
                        $vr->docblock->addKeyword('access', 'private');
801
                        $this->varsbyfile[$file][$class][$i] = $vr;
802
                    }
803
                }
804
                if (isset($this->methodsbyfile[$file])
805
                    && isset($this->methodsbyfile[$file][$class])) {
806
                    foreach ($this->methodsbyfile[$file][$class] as $i => $vr) {
807
                        $vr->docblock->addKeyword('access', 'private');
808
                        $this->methodsbyfile[$file][$class][$i] = $vr;
809
                    }
810
                }
811
                if (isset($this->constsbyfile[$file])
812
                    && isset($this->constsbyfile[$file][$class])) {
813
                    foreach ($this->constsbyfile[$file][$class] as $i => $vr) {
814
                        $vr->docblock->addKeyword('access', 'private');
815
                        $this->constsbyfile[$file][$class][$i] = $vr;
816
                    }
817
                }
818
            }
819
        }
820
        $this->classpathpackages[$class][$file]
821
            = array($db->docblock->package,$db->docblock->subpackage);
822
        if ($db->docblock->getExplicitPackage()) {
823
            $render->proceduralpages->
824
                addClassPackageToFile($file,
825
                    $db->docblock->package, $db->docblock->subpackage);
826
        }
827
        $render->addElementToPage($db, $file);
828
        if (isset($this->varsbyfile[$file])
829
            && isset($this->varsbyfile[$file][$class])) {
830
            foreach ($this->varsbyfile[$file][$class] as $i => $vr) {
831
                $vr->docblock->package    = $db->docblock->package;
832
                $vr->docblock->subpackage = $db->docblock->subpackage;
833
                $render->addElementToPage($vr, $file);
834
                $render->addUses($vr, $file);
835
                $this->varsbyfile[$file][$class][$i]                        = $vr;
836
                $this->vars[$db->docblock->package][$class][$vr->getName()] = $vr;
837
            }
838
        }
839
        if (isset($this->methodsbyfile[$file])
840
            && isset($this->methodsbyfile[$file][$class])) {
841
            foreach ($this->methodsbyfile[$file][$class] as $i => $vr) {
842
                $vr->docblock->package    = $db->docblock->package;
843
                $vr->docblock->subpackage = $db->docblock->subpackage;
844
                $render->addElementToPage($vr, $file);
845
                $render->addUses($vr, $file);
846
                $this->methodsbyfile[$file][$class][$i]                        = $vr;
847
                $this->methods[$db->docblock->package][$class][$vr->getName()] = $vr;
848
            }
849
        }
850
        if (isset($this->constsbyfile[$file])
851
            && isset($this->constsbyfile[$file][$class])) {
852
            foreach ($this->constsbyfile[$file][$class] as $i => $vr) {
853
                $vr->docblock->package    = $db->docblock->package;
854
                $vr->docblock->subpackage = $db->docblock->subpackage;
855
                $render->addElementToPage($vr, $file);
856
                $render->addUses($vr, $file);
857
                $this->constsbyfile[$file][$class][$i]                         = $vr;
858
                $this->methods[$db->docblock->package][$class][$vr->getName()] = $vr;
859
            }
860
        }
861
        $this->classpackages[$class][]
862
            = array($db->docblock->package,$db->docblock->subpackage);
863
        if (is_array($db->parent))
864
            $this->classparents[$db->docblock->package][$class] = $db->parent[1];
865
        else
866
            $this->classparents[$db->docblock->package][$class] = $db->getExtends();
867
        if (is_array($db->parent)) {
868
            $z = $this->getClass($db->parent[1], $db->parent[0]);
869
 
870
            $this->classchildren[$z->docblock->package][$db->parent[1]][] = $db;
871
        }
872
        if (isset($this->classchildrenbyfile[$class])) {
873
            foreach ($this->classchildrenbyfile[$class] as $childfile => $other) {
874
                // test 1, inherits in same file (must be same package)
875
                if ($childfile == $file) {
876
                    foreach ($other as $child => $packages) {
877
                        // debug("parent $class same file $child");
878
                        $this->processChild($render, $child, $childfile);
879
                        $x = $this->getClass($child, $childfile);
880
                        if ($x->docblock->package
881
                            != $GLOBALS['phpDocumentor_DefaultPackageName']) {
882
                            // child package need root for class trees
883
                            if ($x->docblock->package != $db->docblock->package) {
884
                                // debug("adding $child in $childfile 1");
885
                                $this->roots[$child][] = $childfile;
886
                            }
887
                        }
888
                    }
889
                } else {
890
                    // test 2, different file, same package
891
                    foreach ($other as $child => $packages) {
892
                        for ($j=0; $j<count($packages); $j++) {
893
                            if ($this->classesbyfile[$file][$class]->
894
                                    docblock->package == $packages[$j]) {
895
                                $this->processChild($render, $child, $childfile);
896
                                // debug("$childfile diff file $child, parent $class,
897
                                //     same package ".$packages[$j]);
898
                            } else {
899
                                /*
900
                                 * test 3, different file, different package,
901
                                 * only 1 parent is possible
902
                                 */
903
                                if (isset($this->classesbynamefile[$child])) {
904
                                    // 1 possible parent
905
                                    if (count($this->classesbynamefile[$class])
906
                                        == 1) {
907
                                        // debug("$childfile diff file $child,
908
                                        //        diff package,
909
                                        //        1 possible parent root $class");
910
                                        $this->processChild($render,
911
                                            $child, $childfile);
912
                                        $x = $this->getClass($child, $childfile);
913
                                        if ($x->docblock->package
914
                                          != $GLOBALS
915
                                          ['phpDocumentor_DefaultPackageName']) {
916
                                            // child package need root
917
                                            //for class trees
918
                                            if ($x->docblock->package
919
                                                != $db->docblock->package) {
920
                                                // debug("adding roots
921
                                                // $child in $childfile 2");
922
                                                $this->roots[$child][] = $childfile;
923
                                            }
924
                                        }
925
                                    }
926
                                }
927
                            }
928
                        }
929
                    }
930
                }
931
            }
932
        }
933
    }
934
 
935
    /**
936
     * Get the parserClass representation of a class from its name and file
937
     *
938
     * @param string $class classname
939
     * @param string $file  file classname is located in
940
     *
941
     * @return parserClass
942
     */
943
    function &getClass($class, $file)
944
    {
945
        // debug("getClass called with class $class file $file");
946
        return $this->classesbyfile[$file][$class];
947
    }
948
 
949
    /**
950
     * Used by {@link parserData::getClasses()}
951
     * to retrieve classes defined in file $path
952
     *
953
     * retrieves the array entry from {@link $classesbyfile} for $path
954
     *
955
     * @param string $path full path to filename
956
     *
957
     * @return mixed returns false if no classes defined in the file,
958
     *               otherwise returns an array of {@link parserClass}es
959
     */
960
    function getClassesInPath($path)
961
    {
962
        if (!isset($this->classesbyfile[$path])) return false;
963
        return $this->classesbyfile[$path];
964
    }
965
 
966
    /**
967
     * called by {@link parserClass::hasMethods()}.  Should not be directly called
968
     *
969
     * @param string $file  file classname is located in
970
     * @param string $class classname
971
     *
972
     * @return bool
973
     * @access private
974
     */
975
    function hasMethods($file, $class)
976
    {
977
        return isset($this->methodsbyfile[$file][$class]);
978
    }
979
 
980
    /**
981
     * called by {@link parserClass::hasConsts()}.
982
     * Should not be directly called
983
     *
984
     * @param string $file  file classname is located in
985
     * @param string $class classname
986
     *
987
     * @return bool
988
     * @access private
989
     */
990
    function hasConsts($file,$class)
991
    {
992
        return isset($this->constsbyfile[$file][$class]);
993
    }
994
 
995
    /**
996
     * called by {@link parserClass::hasVars()}.  Should not be directly called
997
     *
998
     * @param string $file  file classname is located in
999
     * @param string $class classname
1000
     *
1001
     * @return bool
1002
     * @access private
1003
     */
1004
    function hasVars($file, $class)
1005
    {
1006
        return isset($this->varsbyfile[$file][$class]);
1007
    }
1008
 
1009
    /**
1010
     * called by {@link parserClass::hasMethod()}.  Should not be directly called
1011
     *
1012
     * @param string $class classname
1013
     * @param string $file  file classname is located in
1014
     * @param string $name  method name
1015
     *
1016
     * @return bool
1017
     * @access private
1018
     */
1019
    function hasMethod($class, $file, $name)
1020
    {
1021
        if (!$this->hasMethods($file, $class)) return false;
1022
        for ($i=0; $i<count($this->methodsbyfile[$file][$class]); $i++) {
1023
            if ($this->methodsbyfile[$file][$class][$i]->getName() == $name)
1024
               return true;
1025
        }
1026
        return false;
1027
    }
1028
 
1029
    /**
1030
     * called by {@link parserClass::hasVar()}.  Should not be directly called
1031
     *
1032
     * @param string $class classname
1033
     * @param string $file  file classname is located in
1034
     * @param string $name  var name
1035
     *
1036
     * @return bool
1037
     * @access private
1038
     */
1039
    function hasVar($class, $file, $name)
1040
    {
1041
        if (!$this->hasVars($file, $class)) return false;
1042
        for ($i=0; $i<count($this->varsbyfile[$file][$class]); $i++) {
1043
            if ($this->varsbyfile[$file][$class][$i]->getName() == $name)
1044
                return true;
1045
        }
1046
        return false;
1047
    }
1048
 
1049
    /**
1050
     * called by {@link parserClass::hasConst()}.  Should not be directly called
1051
     *
1052
     * @param string $class classname
1053
     * @param string $file  file classname is located in
1054
     * @param string $name  constant name
1055
     *
1056
     * @return bool
1057
     * @access private
1058
     */
1059
    function hasConst($class, $file, $name)
1060
    {
1061
        if (!$this->hasConsts($file, $class)) return false;
1062
        for ($i=0; $i<count($this->constsbyfile[$file][$class]); $i++) {
1063
            if ($this->constsbyfile[$file][$class][$i]->getName() == $name)
1064
                return true;
1065
        }
1066
        return false;
1067
    }
1068
 
1069
    /**
1070
     * called by {@link parserClass::getMethods()}.  Should not be directly called
1071
     *
1072
     * @param string $class classname
1073
     * @param string $file  file classname is located in
1074
     *
1075
     * @return mixed
1076
     * @access private
1077
     */
1078
    function &getMethods($class, $file)
1079
    {
1080
        if (!isset($this->methodsbyfile[$file][$class])) {
1081
            $flag = false;
1082
            return $flag;
1083
        }
1084
        return $this->methodsbyfile[$file][$class];
1085
    }
1086
 
1087
    /**
1088
     * called by {@link parserClass::getVars()}.  Should not be directly called
1089
     *
1090
     * @param string $class classname
1091
     * @param string $file  file classname is located in
1092
     *
1093
     * @return mixed
1094
     * @access private
1095
     */
1096
    function &getVars($class, $file)
1097
    {
1098
        if (!isset($this->varsbyfile[$file][$class])) {
1099
            $flag = false;
1100
            return $flag;
1101
        }
1102
        return $this->varsbyfile[$file][$class];
1103
    }
1104
 
1105
    /**
1106
     * called by {@link parserClass::getConsts()}.  Should not be directly called
1107
     *
1108
     * @param string $class classname
1109
     * @param string $file  file classname is located in
1110
     *
1111
     * @return mixed
1112
     * @access private
1113
     */
1114
    function &getConsts($class, $file)
1115
    {
1116
        if (!isset($this->constsbyfile[$file][$class])) {
1117
            $flag = false;
1118
            return $flag;
1119
        }
1120
        return $this->constsbyfile[$file][$class];
1121
    }
1122
 
1123
    /**
1124
     * called by {@link parserClass::getMethod()}.  Should not be directly called
1125
     *
1126
     * @param string $class classname
1127
     * @param string $file  file classname is located in
1128
     * @param string $name  method name
1129
     *
1130
     * @return mixed
1131
     * @access private
1132
     */
1133
    function getMethod($class, $file, $name)
1134
    {
1135
        if (!$this->hasMethod($class, $file, $name)) return false;
1136
        for ($i=0; $i<count($this->methodsbyfile[$file][$class]); $i++) {
1137
            if ($this->methodsbyfile[$file][$class][$i]->getName() == $name)
1138
                return $this->methodsbyfile[$file][$class][$i];
1139
        }
1140
    }
1141
 
1142
    /**
1143
     * called by {@link parserClass::getVar()}.  Should not be directly called
1144
     *
1145
     * @param string $class classname
1146
     * @param string $file  file classname is located in
1147
     * @param string $name  var name
1148
     *
1149
     * @return mixed
1150
     * @access private
1151
     */
1152
    function getVar($class, $file, $name)
1153
    {
1154
        if (!$this->hasVar($class, $file, $name)) return false;
1155
        for ($i=0; $i<count($this->varsbyfile[$file][$class]); $i++) {
1156
            if ($this->varsbyfile[$file][$class][$i]->getName() == $name)
1157
                return $this->varsbyfile[$file][$class][$i];
1158
        }
1159
    }
1160
 
1161
    /**
1162
     * called by {@link parserClass::getConst()}.  Should not be directly called
1163
     *
1164
     * @param string $class classname
1165
     * @param string $file  file classname is located in
1166
     * @param string $name  const name
1167
     *
1168
     * @return mixed
1169
     * @access private
1170
     */
1171
    function getConst($class, $file, $name)
1172
    {
1173
        if (!$this->hasConst($class, $file, $name)) return false;
1174
        for ($i=0; $i<count($this->constsbyfile[$file][$class]); $i++) {
1175
            if ($this->constsbyfile[$file][$class][$i]->getName() == $name)
1176
                return $this->constsbyfile[$file][$class][$i];
1177
        }
1178
    }
1179
 
1180
    /**
1181
     * Search for a class in a package
1182
     *
1183
     * @param string $class   classname
1184
     * @param string $package package classname is in
1185
     *
1186
     * @return mixed returns false if no class in $package,
1187
     *               otherwise returns a {@link parserClass}
1188
     */
1189
    function &getClassByPackage($class, $package)
1190
    {
1191
        if (!isset($this->classesbynamefile[$class])) {
1192
            // removed, too many warnings, not very useful
1193
            // addWarning(PDERROR_CLASS_NOT_IN_PACKAGE,$class,$package);
1194
 
1195
            $flag = false;
1196
            return $flag;
1197
        }
1198
        for ($i=0; $i < count($this->classesbynamefile[$class]); $i++) {
1199
            $cls =
1200
                $this->classesbyfile[$this->classesbynamefile[$class][$i]][$class];
1201
            $pkg = $cls->getPackage();
1202
            if ($pkg == $package)
1203
                return $cls;
1204
        }
1205
        // addWarning(PDERROR_CLASS_NOT_IN_PACKAGE,$class,$package);
1206
 
1207
        $flag = false;
1208
        return $flag;
1209
    }
1210
 
1211
    /**
1212
     * Find the parent class of a class in file $file
1213
     * uses 3 tests to find the parent classname:
1214
     * <ol>
1215
     *    <li>only one class with the parent classname</li>
1216
     *    <li>more than one class, but only one in the same file as the child</li>
1217
     *    <li>only one parent class in the same package as the child</li>
1218
     * </ol>
1219
     *
1220
     * @param string $class classname
1221
     * @param string $file  file classname is located in
1222
     *
1223
     * @return mixed false if no parent class,
1224
     *               a string if no parent class found by that name,
1225
     *               and an array(file parentclass is in, parentclassname)
1226
     */
1227
    function getParentClass($class,$file)
1228
    {
1229
        if (!isset($this->classesbyfile[$file][$class])) {
1230
            return false;
1231
        }
1232
        $element = $this->classesbyfile[$file][$class];
1233
        if (!($ex = $element->getExtends())) return false;
1234
        // first check to see if there is one and only one
1235
        // class with the parent class's name
1236
        if (isset($this->classesbynamefile[$ex])) {
1237
            if (count($this->classesbynamefile[$ex]) == 1) {
1238
                if ($this->classesbyfile
1239
                    [$this->classesbynamefile[$ex][0]][$ex]->ignore) {
1240
                    return $ex;
1241
                }
1242
                return array($this->classesbynamefile[$ex][0],$ex);
1243
            } else {
1244
                // next check to see if there is a parent class in the same file
1245
                if (isset($this->classesbyfile[$file][$ex])) {
1246
                    if ($this->classesbyfile[$file][$ex]->ignore) {
1247
                        return $ex;
1248
                    }
1249
                    return array($file,$ex);
1250
                }
1251
                // next check to see if there is only one package
1252
                // used in the file, try to resolve it that way
1253
                if (isset($this->classpackagebyfile[$file])) {
1254
                    if (count($this->classpackagebyfile[$file]) == 1) {
1255
                        for ($i=0;$i<count($this->classesbynamefile[$ex]);$i++) {
1256
                            if ($this->classesbyfile
1257
                              [$this->classesbynamefile[$ex][$i]][$ex]->getPackage()
1258
                               == $this->classpackagebyfile[$file][0]) {
1259
                                if ($this->classesbyfile
1260
                                   [$this->classesbynamefile[$ex][$i]][$ex]->ignore)
1261
                                    return $ex;
1262
                                return array($this->classesbynamefile[$ex][$i],$ex);
1263
                            }
1264
                        }
1265
                    }
1266
                }
1267
                // name conflict
1268
                addWarning(PDERROR_INHERITANCE_CONFLICT, $class, $file, $ex);
1269
                return $ex;
1270
            }
1271
        } else {
1272
            if (class_exists('ReflectionClass') && class_exists($ex)) {
1273
                $r = new ReflectionClass($ex);
1274
                if ($r->isInternal()) {
1275
                    return $ex; // no warning
1276
                }
1277
            }
1278
            addWarning(PDERROR_PARENT_NOT_FOUND, $class, $ex);
1279
            return $ex;
1280
        }
1281
    }
1282
 
1283
    /**
1284
     * Get a list of all root classes indexed by package.  Used to generate
1285
     * class trees by {@link Converter}
1286
     *
1287
     * @param boolean $all [since phpDocumentor 1.3.0RC6] determines whether to
1288
     *                     return class trees that extend non-parsed classes
1289
     *
1290
     * @return array array(package => array(rootclassname, rootclassname,...),...)
1291
     */
1292
    function getRoots($all = false)
1293
    {
1294
        $roots     = array();
1295
        $temproots = $this->roots;
1296
        if (!$all) {
1297
            foreach ($this->specialRoots as $package => $root) {
1298
                foreach ($root as $parent => $info) {
1299
                    $temproots[$info[0]][] = $info[1];
1300
                }
1301
            }
1302
        }
1303
        foreach ($temproots as $class => $files) {
1304
            if (count($files)) {
1305
                foreach ($files as $i => $boofou) {
1306
                    $x = $this->getClass($class, $files[$i]);
1307
 
1308
                    $roots[$x->getPackage()][] = $class;
1309
                }
1310
            }
1311
        }
1312
        foreach ($roots as $package => $root) {
1313
            usort($roots[$package], "strnatcasecmp");
1314
        }
1315
        if ($all) {
1316
            $specialRoots = array();
1317
            foreach ($this->specialRoots as $parent => $classinfo) {
1318
                if (count($classinfo)) {
1319
                    foreach ($classinfo as $i => $info) {
1320
                        $x = $this->getClass($info[0], $info[1]);
1321
 
1322
                        $specialRoots[$x->getPackage()][$parent][] = $info[0];
1323
                    }
1324
                }
1325
            }
1326
            foreach ($specialRoots as $package => $root) {
1327
                uksort($specialRoots[$package], "strnatcasecmp");
1328
                foreach ($specialRoots[$package] as $parent => $classes) {
1329
                    usort($specialRoots[$package][$parent], 'strnatcasecmp');
1330
                }
1331
            }
1332
            return array('special' => $specialRoots, 'normal' => $roots);
1333
        }
1334
        return $roots;
1335
    }
1336
 
1337
    /**
1338
     * Get all classes confirmed in parsing
1339
     * to be descended class $parclass in file $file
1340
     *
1341
     * @param string $parclass name of parent class
1342
     * @param string $file     file parent class is found in
1343
     *
1344
     * @return mixed either false if no children, or array of format
1345
     *         array(childname => childfile,childname2 => childfile2,...)
1346
     * @see parserClass::getChildClassList()
1347
     * @uses $definitechild
1348
     */
1349
    function getDefiniteChildren($parclass, $file)
1350
    {
1351
        if (isset($this->definitechild[$parclass][$file]))
1352
            return $this->definitechild[$parclass][$file];
1353
        return false;
1354
    }
1355
}
1356
?>