[PHP] Javadoc-style commentblok op keywords uitlezen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb een groot aantal php bestanden met een javadoc-style beschrijving bovenin:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
/**
 * @file
 * Provides a toolbar that shows the top-level administration menu items and 
 * links from other modules.
 * 
 * Hier zou nog meer file-info kunnen staan.
 *
 * @author  tweakerert <tweakerert@hotmail.com>
 * @version 23:47 29-12-2009
 * @todo    make some clever additions
 * @example admin.menu.toolbar([array])
 */

De vorm is altijd hetzelfde: achter elk @keyword volgt direct de inhoud, behalve bij @file (want daar zit een newline achter). Ik wil nu de waardes van @file en @version uitlezen. Momenteel doe ik dat met onderstaande functie.

Omdat het aantal newlines bij de @file inhoud onbekend is, wordt alles gepakt tot aan @author. Hier zijn twee problemen mee: de description bevat nu ook telkens de string "@file". Hoe kan ik die eruit laten?

Ten tweede: als iemand nu eens niet de @author tag als eerste keyword gebruikt na @file, loopt dit in de soep. Ik zit eraan te denken of er geen generiekere manier is om een commentblok uit te lezen. Zo zou ik een array kunnen maken met alle toegestane keywords (@file, @author, @version, @todo, etc.) en dan alle keywords met een generieke regex uitlezen en in een array stoppen. Dan kan ik daarna kijken welke ik wel of niet wil doorsturen naar een andere functie.

Een vraag hierbij is: is zo'n generieke regex de beste oplossing hier en wie kan mij daar eventueel mee op weg helpen?

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function module_info() {
  $return = array();

  foreach (module_list() as $module) {
    $data = implode('', file(MODULE_PATH. "$module/$module.module"));

    preg_match('/\/\*\*(.+)(?=@author)/is', $data, $description);
    preg_match('/@version(.*)/i', $data, $version);

    $description = trim(preg_replace('/\r?\n *\* */', ' ', $description[1]));
    $version     = trim($version[1]); 
    
    if (isset($description) && isset($version)) {
      $return[] = array(
        'description' => $description, 
        'version' => $version
      );
    }
  }
  return $return;
}

Acties:
  • 0 Henk 'm!

  • orf
  • Registratie: Augustus 2005
  • Laatst online: 22:53

orf

Kijk eens naar de Reflection API (standaard in PHP5) en de uitbreiding daarop in Zend Framework. Een generieke regex is niet zo'n goede oplossing.

Acties:
  • 0 Henk 'm!

  • Freeaqingme
  • Registratie: April 2006
  • Laatst online: 18-09 15:55
Overigens heet dit in de PHP-wereld gewoon phpDoc. javaDoc in php is ook zo vreemd ;)

No trees were harmed in creating this message. However, a large number of electrons were terribly inconvenienced.


Acties:
  • 0 Henk 'm!

  • eghie
  • Registratie: Februari 2002
  • Niet online

eghie

Spoken words!


Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 00:17
Overigens is de kans groot dat je met phpDocumentor precies de uitvoer kunt krijgen die je hebben wil :)

Regeren is vooruitschuiven


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
T-MOB schreef op zondag 21 februari 2010 @ 12:54:
Overigens is de kans groot dat je met phpDocumentor precies de uitvoer kunt krijgen die je hebben wil :)
Ja, maar ik zoek een implementatie voor binnen mijn eigen cms'je. In het commentblok staat de werking en versie van elke module van het systeem. Als een (geauthoriseerde) gebruiker op 'admin/modules/info' klikt, wil ik hem een overzicht geven van alle op het systeem geinstalleerde modules, met beschrijving en versienummer. Vergelijk het met 'add/remove programs' binnen Windows.

Ik had dus een eigen functie, (zie topicstart), maar deze blijkt niet goed genoeg. Vandaar dit topic, voor tips over hoe te verbeteren :)

Acties:
  • 0 Henk 'm!

Verwijderd

Verwijderd schreef op zondag 21 februari 2010 @ 14:01:
[...]

Ja, maar ik zoek een implementatie voor binnen mijn eigen cms'je. In het commentblok staat de werking en versie van elke module van het systeem. Als een (geauthoriseerde) gebruiker op 'admin/modules/info' klikt, wil ik hem een overzicht geven van alle op het systeem geinstalleerde modules, met beschrijving en versienummer. Vergelijk het met 'add/remove programs' binnen Windows.

Ik had dus een eigen functie, (zie topicstart), maar deze blijkt niet goed genoeg. Vandaar dit topic, voor tips over hoe te verbeteren :)
orf geeft de oplossing al:
orf schreef op zaterdag 20 februari 2010 @ 20:59:
Kijk eens naar de Reflection API (standaard in PHP5) en de uitbreiding daarop in Zend Framework. Een generieke regex is niet zo'n goede oplossing.
De Zend_Reflection classes kunnen ook omgaan met 'docblocks' en annotations, hoef je alleen nog maar te bepalen welke bestanden je wilt bekijken en welke annotations je wilt weergeven. Bovendien heb je niet het hele framework nodig, maar wss enkel de Zend_Reflection classes

[ Voor 3% gewijzigd door Verwijderd op 21-02-2010 15:24 ]


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:47
Ik zou beginnen met een preprocessing stap om een commentaarblok te identificeren en vervolgens de commentaardelimiters (/* en */ en de sterretjes aan het begin van de regel) weg te gooien. Die code heb je in principe al. Dan krijg je dus een string met een aantal regels, bijvoorbeeld:
code:
1
2
3
4
5
6
7
8
9
10
@file
Provides a toolbar that shows the top-level administration menu items and 
links from other modules.

Hier zou nog meer file-info kunnen staan.

@author  tweakerert <tweakerert@hotmail.com>
@version 23:47 29-12-2009
@todo    make some clever additions
@example admin.menu.toolbar([array])

Die data kun je indelen in blokken, door te splitsen op een reguliere expressie als ^\s*@[a-z]+\s+ (of iets dergelijks) met preg-split. Daarbij wil je de delimiters ook capturen (zie de PREG_SPLIT_DELIM_CAPTURE optie). Dan krijg je zo'n soort array:
PHP:
1
array( "", "@file\n", "Provides...", "@author  ", "tweakerert", "@version", "23:47..", ..

Het eerste element is leading whitespace (of andere ongetagte tekst). Die gooi je weg. De andere elementen zijn om en om keys en values. Die kun je makkelijk in een associatieve array mikken om het gewenste resultaat te krijgen. (Wel nog even whitespace om keys en values trimmen.)

Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Soultaker schreef op zondag 21 februari 2010 @ 16:45:
Dan krijg je dus een string met een aantal regels, bijvoorbeeld:
[...]
Die data kun je indelen in blokken, door te splitsen op een reguliere expressie als ^\s*@[a-z]+\s+ (of iets dergelijks) met preg-split.
Nah, als je die data hebt, dan zou ik toch liever gewoon met preg_match werken. Iets als:
PHP:
1
2
3
preg_match_all('/@([a-z]++)\s++((?:[^@\s]++|\s*+(?:[^@]|@(?![a-z]++\s)))++)/',
    $comment, $matches);
$info = array_combine($matches[1], $matches[2]);

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:47
Dat heeft dus als nadeel dat je handmatig de non-greedy matching erin moet hacken. Vergelijk jouw regexp eens met de mijne; dat ding is vier keer zo lang en bepaald niet leesbaar. ;) Dan kun je mijns inziens beter een beetje handmatige postprocessing doen, dan alles met reguliere expressies te willen doen.
pedorus schreef op zondag 21 februari 2010 @ 19:37:
... in beide gevallen zal wat commentaar op zijn plaats zijn. :p
Ook een manier om 't te formuleren. :P

[ Voor 27% gewijzigd door Soultaker op 21-02-2010 20:03 ]


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Het kan ook wat korter, maar dan krijg je waarschijnlijk slechtere performance (ongetest):
PHP:
1
preg_match_all('/@([a-z]+)\s+(.*?)\s*(?=$|@[a-z]+\s)/s', $comment, $matches);
En ja, in beide gevallen zal wat commentaar op zijn plaats zijn. :p

[ Voor 6% gewijzigd door pedorus op 21-02-2010 19:49 . Reden: dezelfde->waarschijnlijk ]

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten

Pagina: 1