Skip to content

Commit adf6bc4

Browse files
committed
update class and readme
1 parent 49b91dc commit adf6bc4

File tree

3 files changed

+121
-25
lines changed

3 files changed

+121
-25
lines changed

Readme.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# PHP Doc generator (BETA)
1+
# PHP Doc generator
22

33
A class and cli script to generate a markdown doc page from a class file.
44

55
You can customize the output or create output in another wanted format.
66

7-
Compatible to PHP 8.3
7+
Compatible to PHP 8.4
88

99
👤 Author: Axel Hahn \
1010
📄 Source: <https://github.com/axelhahn/php-classdoc> \

parse-class.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* @source <https://github.com/axelhahn/php-classdoc>
1010
*
1111
* 2024-07-15 v0.1 axelhahn initial version
12+
* 2025-07-21 axelhahn
1213
*/
1314

1415
// ------------------------------------------------------------
@@ -143,7 +144,9 @@ function showHelp(){
143144
_wd("Init parser with param 2: $sClass");
144145
$oParser->setClassname($sClass);
145146
}
146-
147+
if($sourceurl){
148+
$oParser->setSourceUrl($sourceurl);
149+
}
147150
// ---------- generate output
148151

149152
$sOut="";

src/phpclass-parser.class.php

Lines changed: 115 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ public function setClassFile(string $file): bool|string
5858

5959
// remove all php comments
6060
$commentTokens = [T_COMMENT];
61-
61+
6262
if (defined('T_DOC_COMMENT')) {
6363
$commentTokens[] = T_DOC_COMMENT; // PHP 5
64-
}
64+
}
6565
if (defined('T_ML_COMMENT')) {
6666
$commentTokens[] = T_ML_COMMENT; // PHP 4
6767
}
6868
$tokens = token_get_all($sFiledata);
69-
foreach ($tokens as $token) {
69+
foreach ($tokens as $token) {
7070
if (is_array($token)) {
7171
if (in_array($token[0], $commentTokens)) {
7272
continue;
@@ -142,7 +142,15 @@ public function setClassname(string $sClassname): void
142142
}
143143
}
144144

145+
public function setSourceUrl(string $sSourceUrl): void
146+
{
147+
$this->sSourceUrl = $sSourceUrl;
148+
}
145149

150+
/**
151+
* Get metainformation for the class
152+
* @return array
153+
*/
146154
public function getClassInfos(): array
147155
{
148156
$aReturn = [];
@@ -152,6 +160,8 @@ public function getClassInfos(): array
152160
$aReturn['classname'] = $this->sClassname;
153161
$aReturn['namespace'] = $this->oRefClass->getNamespaceName();
154162
$aReturn['phpdoc'] = $this->parsePhpdocBlock($this->oRefClass->getDocComment());
163+
// $aReturn['comment'] = $aReturn['phpdoc']['filtered'];
164+
$aReturn['comment'] = $aReturn['phpdoc']['raw'];
155165
$aReturn['comment'] = $aReturn['phpdoc']['filtered'];
156166

157167
return $aReturn;
@@ -204,6 +214,10 @@ public function getMethods($bPublicOnly = true): array
204214
? trim($aPhpDoc['tags']['param'][$iCount - 1])
205215
: ''
206216
;
217+
218+
$sStringValue=($iCount <= $iRequired ? '\<required\>' : '\<optional\>')
219+
. ' $'.$oParam->getName()
220+
;
207221
// see https://www.php.net/manual/en/class.reflectionparameter.php
208222
$aParam = [
209223
'name' => $oParam->getName(),
@@ -212,23 +226,28 @@ public function getMethods($bPublicOnly = true): array
212226
'required' => $iCount <= $iRequired,
213227
'default' => $iCount <= $iRequired ? NULL : $oParam->getDefaultValue(),
214228
'raw' => $oParam->__toString(),
229+
/*
215230
'string' => str_replace(
216231
['<', '>'],
217232
['\<', '\>'],
218233
preg_replace('@Parameter\ \#.*\[\ (.*)\ \]@', '$1', $oParam->__toString())
219234
),
235+
*/
236+
'string' => $sStringValue,
220237
];
221238
$aParam['phpdoc'] = $sPhpDoc4Param;
222239
$aParam['phpdoc_line'] = $sPhpDoc4Param;
223240
$aParam['phpdoc_type'] = $sPhpDoc4Param
224241
? preg_replace('/ .*/', '', $sPhpDoc4Param)
225242
: ''
226243
;
227-
$aParam['phpdoc_descr'] = ($sPhpDoc4Param
228-
? preg_replace('/^[a-z]* [\$A-Za-z0-9]* /', '', $sPhpDoc4Param)
229-
: ''
230-
)
231-
;
244+
// $aParam['phpdoc_descr'] = ($sPhpDoc4Param
245+
// ? preg_replace('/^[a-z]* [\$A-Za-z0-9]* /', '', $sPhpDoc4Param)
246+
// : ''
247+
// )
248+
// ;
249+
$aParam['phpdoc_descr'] = str_replace(chr(13), '<br>', $sPhpDoc4Param);
250+
232251
$aParam['type'] = $aParam['type']
233252
? $aParam['type']
234253
: $aParam['phpdoc_type'] . ' *'
@@ -244,7 +263,9 @@ public function getMethods($bPublicOnly = true): array
244263
'linefrom' => $o->getStartLine(),
245264
'lineto' => $o->getEndLine(),
246265
'lines' => $o->getEndLine() - $o->getStartLine() + 1,
266+
'sourceurl' => $this->sSourceUrl ? $this->sSourceUrl."#L".$o->getStartLine() : "",
247267
'comment' => $aPhpDoc['comment'] ?? '',
268+
'raw' => $aPhpDoc['raw'] ?? '',
248269
'parameters_count' => $oMethod->getNumberOfParameters(),
249270
'parameters_required' => $oMethod->getNumberOfRequiredParameters(),
250271
'parameters' => $aParams,
@@ -260,6 +281,7 @@ public function getMethods($bPublicOnly = true): array
260281
)
261282
)
262283
;
284+
$aMethod['returntype'] = $aMethod['returntype']?:'void';
263285

264286
$aReturn[$sMethodname] = $aMethod;
265287
}
@@ -352,16 +374,57 @@ private function parsePhpdocBlock($sPhpDoc)
352374
{
353375
$aReturn = [];
354376

377+
/*
378+
$tokens = token_get_all('<?php '.$sPhpDoc);
379+
380+
foreach ($tokens as $token) {
381+
if (is_array($token)) {
382+
echo "Line {$token[2]}: ", token_name($token[0]), " ('{$token[1]}')", PHP_EOL;
383+
}
384+
}
385+
*/
386+
355387
$sFiltered = $sPhpDoc;
356-
$sFiltered = preg_replace('@[\ \t][\ \t]*@', ' ', $sFiltered); // remove multiple spaces
357388

358389
$sFiltered = preg_replace('@^\/\*\*@', '', $sFiltered); // remove first comment line
359390
$sFiltered = preg_replace('@.*\*\/@', '', $sFiltered); // remove last comment line
360-
$sFiltered = preg_replace('@ \* @', '', $sFiltered); // remove " * "
361-
$sFiltered = preg_replace('@ \*@', '', $sFiltered); // remove " *"
362-
// $sFiltered=preg_replace('@\n@', '<br>', $sFiltered);
363-
// $sFiltered=preg_replace('@^\<br\>@', '', $sFiltered);
364391

392+
$sFiltered = preg_replace('@[\ \t]*\*@', '', $sFiltered); // remove " * "
393+
// $sFiltered = preg_replace('@\n @', '', $sFiltered); // remove leading spaces
394+
395+
396+
// TODO: put filter to output specific configuration
397+
$sFiltered = str_replace(['<code>', '</code>'], ["\n\n```txt ", "```\n\n"], $sFiltered);
398+
$sFiltered = preg_replace('@ *\n@', "\n", $sFiltered); // remove
399+
400+
$iStart = strpos($sFiltered, '@param');
401+
if (!$iStart) $iStart = strpos($sFiltered, '@return');
402+
$sComment = $iStart ? substr($sFiltered, 0, $iStart) : $sFiltered;
403+
404+
$sParams = substr($sFiltered, $iStart);
405+
$aReturn = [
406+
'raw' => $sPhpDoc,
407+
'filtered' => $sFiltered,
408+
// 'comment' => preg_replace('/@(param|return|var).*\n/', '', $sFiltered),
409+
'comment' => trim($sComment),
410+
'params' => $sParams,
411+
'tags' => $this->_parsePhpdocTags($sFiltered),
412+
];
413+
414+
415+
// print_r($aReturn['tags']);
416+
417+
return $aReturn;
418+
}
419+
420+
/**
421+
* Summary of _parsePhpdocTags
422+
* @param string $sFiltered filtered doc block
423+
* @return array
424+
*/
425+
protected function _parsePhpdocTags($sFiltered): array
426+
{
427+
$aReturn = [];
365428
// all @-Tags
366429
$aTags = [
367430
"abstract",
@@ -395,18 +458,48 @@ private function parsePhpdocBlock($sPhpDoc)
395458
"var",
396459
"version"
397460
];
398-
$aReturn = [
399-
//'raw'=>$sPhpDoc,
400-
'filtered' => $sFiltered,
401-
'comment' => trim(preg_replace('/@(param|return|var).*\n/', '', $sFiltered)),
402-
];
403-
foreach ($aTags as $sKey) {
404-
if (preg_match('/@' . $sKey . '/', $sFiltered)) {
405-
preg_match_all('/@' . $sKey . '(.*?)\n/U', $sFiltered, $aMatch);
406-
$aReturn['tags'][$sKey] = $aMatch[1];
461+
462+
463+
// echo "$sFiltered\n\n";
464+
465+
$sMyTag='_comment';
466+
$sTagData='';
467+
$bParseAsFirstLine=false;
468+
foreach(explode('@', $sFiltered) as $sLine){
469+
$sFirstword=explode(' ', $sLine)[0];
470+
if(array_search($sFirstword, $aTags)!==false){
471+
// store collected lines
472+
$aReturn[$sMyTag][]=$sTagData;
473+
$sTagData='';
474+
475+
// start new tag
476+
$sMyTag=$sFirstword;
477+
if ($sMyTag=="param"){
478+
$bParseAsFirstLine=true;
479+
}
480+
}
481+
$sLine=preg_replace("/^$sMyTag */", '', $sLine);
482+
483+
// parse "string $sAppid id of an app"
484+
if($bParseAsFirstLine){
485+
$bParseAsFirstLine=false;
486+
$sTagData.=preg_replace("/^[a-z\|]*[\t ]*\\$[a-zA-Z0-9_]*[\t ]*/", '', $sLine)."\n";
487+
// ^ ^ ^ ^
488+
// type(s) space dollar+varname spaces
489+
} else {
490+
$sTagData.=$sLine;
407491
}
492+
// echo "$sMyTag > $sLine\n";
408493
}
409494

495+
// write last data
496+
$aReturn[$sMyTag][]=$sTagData;
497+
498+
499+
if(strstr($sFiltered, '__Get a flat array with all application ids')){
500+
echo "```txt ".print_r($aReturn, 1). "```\n";
501+
die();
502+
}
410503
return $aReturn;
411504
}
412505

0 commit comments

Comments
 (0)