Skip to content

Commit 4350402

Browse files
committed
Initial working code.
1 parent c183ea0 commit 4350402

File tree

6 files changed

+283
-1
lines changed

6 files changed

+283
-1
lines changed

PHPCtags.class.php

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<?php
2+
class PHPCtags
3+
{
4+
private $mFile;
5+
6+
private $mParser;
7+
8+
public function __construct($file) {
9+
//@todo Check for existence
10+
$this->mFile = $file;
11+
$this->mParser = new PHPParser_Parser(new PHPParser_Lexer);
12+
}
13+
14+
private function getAccess($node)
15+
{
16+
if ($node->isPrivate()) return 'private';
17+
if ($node->isProtected()) return 'protected';
18+
return 'public';
19+
}
20+
21+
private function struct($node, $class_name = NULL, $function_name = NULL)
22+
{
23+
static $structs = array();
24+
25+
$kind = $name = $line = $scope = $access = '';
26+
if (is_array($node)) {
27+
foreach ($node as $subNode) {
28+
$this->struct($subNode, $class_name, $function_name);
29+
}
30+
} elseif ($node instanceof PHPParser_Node_Stmt_Class) {
31+
$kind = 'c';
32+
$name = $node->name;
33+
$line = $node->getLine() - 1;
34+
foreach ($node as $subNode) {
35+
$this->struct($subNode, $name);
36+
}
37+
} elseif ($node instanceof PHPParser_Node_Stmt_Property) {
38+
$kind = 'v';
39+
$prop = $node->props[0];
40+
$name = $prop->name;
41+
$line = $prop->getLine() - 1;
42+
$scope = "class:" . $class_name;
43+
$access = $this->getAccess($node);
44+
} elseif ($node instanceof PHPParser_Node_Stmt_ClassConst) {
45+
$kind = 'd';
46+
$cons = $node->consts[0];
47+
$name = $cons->name;
48+
$line = $cons->getLine() - 1;
49+
$scope = "class:" . $class_name;
50+
} elseif ($node instanceof PHPParser_Node_Stmt_ClassMethod) {
51+
$kind = 'f';
52+
$name = $node->name;
53+
$line = $node->getLine() - 1;
54+
$scope = "class:" . $class_name;
55+
$access = $this->getAccess($node);
56+
foreach ($node as $subNode) {
57+
$this->struct($subNode, $class_name, $name);
58+
}
59+
} elseif ($node instanceof PHPParser_Node_Stmt_Const) {
60+
$kind = 'd';
61+
$cons = $node->consts[0];
62+
$name = $cons->name;
63+
$line = $node->getLine() - 1;
64+
} elseif ($node instanceof PHPParser_Node_Stmt_Global) {
65+
$kind = 'v';
66+
$prop = $node->vars[0];
67+
$name = $prop->name;
68+
$line = $node->getLine() - 1;
69+
} elseif ($node instanceof PHPParser_Node_Stmt_Static) {
70+
//@todo
71+
} elseif ($node instanceof PHPParser_Node_Stmt_Declare) {
72+
//@todo
73+
} elseif ($node instanceof PHPParser_Node_Stmt_Function) {
74+
$kind = 'f';
75+
$name = $node->name;
76+
$line = $node->getLine() - 1;
77+
foreach ($node as $subNode) {
78+
$this->struct($subNode, $class_name, $name);
79+
}
80+
} elseif ($node instanceof PHPParser_Node_Stmt_Trait) {
81+
//@todo
82+
} elseif ($node instanceof PHPParser_Node_Stmt_Interface) {
83+
$kind = 'i';
84+
$name = $node->name;
85+
$line = $node->getLine() - 1;
86+
} elseif ($node instanceof PHPParser_Node_Stmt_Namespace) {
87+
//@todo
88+
} elseif ($node instanceof PHPParser_Node_Expr_Assign) {
89+
$kind = 'v';
90+
$node = $node->var;
91+
$name = $node->name;
92+
$line = $node->getLine() - 1;
93+
if (!empty($class_name) && !empty($function_name)) {
94+
$scope = "function:" . $class_name . '::' . $function_name;
95+
} elseif (!empty($function_name)) {
96+
$scope = "function:" . $function_name;
97+
}
98+
} else {
99+
// we don't care the rest of them.
100+
}
101+
102+
if(!empty($kind) && !empty($name) && !empty($line)) {
103+
$structs[] = array(
104+
'kind' => $kind,
105+
'name' => $name,
106+
'line' => $line,
107+
'scope' => $scope,
108+
'access' => $access,
109+
);
110+
}
111+
112+
return $structs;
113+
}
114+
115+
private function render($structs)
116+
{
117+
$str = '';
118+
$lines = file($this->mFile);
119+
foreach ($structs as $stuct) {
120+
if (empty($stuct['name']) || empty($stuct['line']) || empty($stuct['kind']))
121+
return;
122+
123+
if ($stuct['kind'] == 'v') {
124+
$str .= "$" . $stuct['name'];
125+
} else {
126+
$str .= $stuct['name'];
127+
}
128+
$str .= "\t" . $this->mFile;
129+
$str .= "\t" . "/^" . rtrim($lines[$stuct['line']], "\n") . "$/;\"";
130+
$str .= "\t" . $stuct['kind'];
131+
$str .= "\t" . "line:" . $stuct['line'];
132+
!empty($stuct['scope']) && $str .= "\t" . $stuct['scope'];
133+
!empty($stuct['access']) && $str .= "\t" . "access:" . $stuct['access'];
134+
$str .= "\n";
135+
}
136+
return $str;
137+
}
138+
139+
public function export()
140+
{
141+
$code =file_get_contents($this->mFile);
142+
$stmts = $this->mParser->parse($code);
143+
$structs = $this->struct($stmts);
144+
echo $this->render($structs);
145+
}
146+
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
phpctags
22
========
33

4-
A enhanced php ctags file generator.
4+
An enhanced php ctags file generator.

phpctags

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/php -q
2+
<?php
3+
include __DIR__ . '/PHP-Parser/lib/bootstrap.php';
4+
include __DIR__ . "/PHPCtags.class.php";
5+
6+
$options = getopt('f:',array('version'));
7+
8+
if(isset($options['version'])) {
9+
echo <<<'EOF'
10+
Exuberant Ctags compatiable PHP enhancement, Copyright (C) 2012 Techlive Zheng
11+
Addresses: <techlivezheng@gmail.com>, https://github.com/techlivezheng/phpctags
12+
EOF;
13+
exit;
14+
}
15+
16+
$file = realpath(array_pop($argv));
17+
18+
$ctags = new PHPCtags($file);
19+
$ctags->export();

tests/PHPCtagsTest.example.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
define('GLOBAL_CONST_1','this is a global const.');
4+
5+
// Only available php 5.3+
6+
const GLOBAL_CONST_2 = 'this is a global const too.';
7+
8+
$var1 = 1;
9+
10+
$var2 = 2;
11+
12+
// With a variable define in scope
13+
function function_1() {
14+
$var = 1;
15+
return $var;
16+
}
17+
18+
// Without a variable define in scope
19+
function function_2() {
20+
return function_1();
21+
}
22+
23+
trait Trait_1 {
24+
25+
}
26+
27+
interface Interface_1
28+
{
29+
const CLASS_CONST = 'this is a const defined in this scope';
30+
31+
function method_0();
32+
33+
function method_1();
34+
35+
function method_2();
36+
37+
function method_3();
38+
}
39+
40+
abstract class Class_1 implements Interface_1
41+
{
42+
const CLASS_CONST = 'this is a const defined in this scope';
43+
44+
public $var1;
45+
46+
private $var2;
47+
48+
protected $var3;
49+
50+
function __construct() {
51+
$this->var1 = 1;
52+
$this->var2 = 2;
53+
$this->var3 = 3;
54+
}
55+
56+
function method_0() {
57+
$var = 'this is a method with a variable defined in this scope';
58+
return $var;
59+
}
60+
61+
public function method_1() {
62+
return 'this is a public method.';
63+
}
64+
65+
private function method_2() {
66+
return 'this is a private method.';
67+
}
68+
69+
protected function method_3() {
70+
return 'this is a protected method.';
71+
}
72+
}
73+
74+
class Class_2 extends Class_1
75+
{
76+
77+
}

tests/PHPCtagsTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
/**
3+
* Generated by PHPUnit_SkeletonGenerator on 2012-07-10 at 02:00:19.
4+
*/
5+
class PHPCtagsTest extends PHPUnit_Framework_TestCase
6+
{
7+
/**
8+
* @var PHPCtags
9+
*/
10+
protected $object;
11+
12+
/**
13+
* Sets up the fixture, for example, opens a network connection.
14+
* This method is called before a test is executed.
15+
*/
16+
protected function setUp()
17+
{
18+
$this->object = new PHPCtags(__DIR__ . '/PHPCtagsTest.example.php');
19+
}
20+
21+
/**
22+
* Tears down the fixture, for example, closes a network connection.
23+
* This method is called after a test is executed.
24+
*/
25+
protected function tearDown()
26+
{
27+
}
28+
29+
/**
30+
* @covers PHPCtags::export
31+
*/
32+
public function testExport()
33+
{
34+
$this->object->export();
35+
}
36+
37+
}

tests/bootstrap.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?php
2+
include __DIR__ . '/../PHP-Parser/lib/bootstrap.php';
3+
include __DIR__ . "/../PHPCtags.class.php";

0 commit comments

Comments
 (0)