[PHP] PHP Commentaar regels opzoeken en filteren

Pagina: 1
Acties:
  • 130 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Van sommige functies binnen mijn cms wil ik een beschrijving beschikbaar maken voor de gebruiker. Neem aan dat al deze functies eindigen op "_ding":
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * @description Retourneert een foo-bericht naar de gebruiker
 * @user Met deze functie kunt u mooi dingen doen.
 *   Hele mooie dingen!
 */
function foo_ding() {
  return 'foo!';
}

/**
 * @user Deze functie doet iets stoms. Iets heel erg stoms!
 * @version Retourneert een bar-bericht naar de gebruiker
 */
function bar_ding() {
  return 'bar!';
}

Ik probeer al een hele tijd een functie te schrijven die mijn code doorloopt en de _ding-functies eruit plukt. Vervolgens moet de functie kijken in het commentaar van die functie (die staat er altijd direct boven) en alle informatie die achter @user staat eruit vissen. Om de _dingen functies te verzamelen heb ik de volgende functie gemaakt:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
function get_dingen() {
  $func = get_defined_functions();
  $func = $func['user'];
  
  foreach ($func as $val) {
    if (substr($val, -5, 5) == '_ding') {
      $dingen[] = $val;
    }
  }

  return $dingen;
}

Dat werkt goed. Ik krijg een array terug met alle functies die op "_ding" eindigen. Vervolgens ben ik begonnen aan een functie om het commentaar uit te lezen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function dingen_info()
{
  foreach (get_dingen() as $ding)
  {
    /* Zoek de functie op en ga dan een x aantal regels omhoog
     * in het bestand totdat je @user tegenkomt. Verzamel de
     * info achter @user totdat je een andere "@" tegenkomt of
     * totdat je een * direct gevolgd door een / tegenkomt */

    preg_match('/@user(.*)/i', $data, $name);
    $user = trim($user[1]);
    $info[$ding] = $user;
  }
  return $ding;
}

Ik heb alleen geen idee hoe ik moet bepalen waar een functie staat en hoe ik dan terug omhoog kan lopen in dat bestand tot ik @user tegenkom. De preg_match is opzich wel goed denk ik, maar voor de rest zit ik vast. Wie kan mij op weg helpen?

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Simpele gedachte, zoek eerst naar commentaar, kijk dan of er op de regel daarna een _ding staat zoja doe dan iets met het commentaar anders commentaar negeren. En dit tot eof doen.

Omgekeerde redenering, maar ik ga ervan uit dat je een bestand van boven naar beneden inleest, dus beginnen bij eerst zoeken naar het 1e element ( commentaar ) en dan pas naar het 2e element ook al is het 2e element belangrijker.

Acties:
  • 0 Henk 'm!

Verwijderd

Probeer het eens met de Tokenizer extensie deze is standaard beschikbaar vanaf PHP versie 4.3.0. Bij de nl beschrijving staat een voorbeeld die comment verwijderd.

De tokenizer verdeeld de code in een array met tokens. Een token is b.v. een comment regel of de declaratie van een functie. Eigenlijk is het gewoon de Zend Engine die kijkt wat er allemaal in je code zit.

[ Voor 49% gewijzigd door Verwijderd op 08-06-2005 22:36 ]


Acties:
  • 0 Henk 'm!

  • Brakkie
  • Registratie: Maart 2001
  • Niet online

Brakkie

blaat

Wellicht geheel ten overvloede maar misschien toch van waarde: http://pear.php.net/package/PhpDocumentor/

Pear klasse die documentatie genereerd in javadoc stijl. Wie weet is dit aan te passen aan jouw wensen.

Systeem | Strava


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Mocht je PHP5 gebruiken, de Reflection API heeft ook de mogenlijkheid om het commentaar er uit te vissen. (ReflectionClass::getDocComment(), ReflectionMethod::getDocComment() en ReflectionFunction::getDocComment())

Acties:
  • 0 Henk 'm!

  • frickY
  • Registratie: Juli 2001
  • Laatst online: 18-09 14:42
Lijkt me dat je gewoon met een eregi kunt matchen;

PHP:
1
2
3
4
while(eregi("@user([[:print:]]*)function [A-Z]*_ding()", $file, $regs) {
  echo "Gevonden comment: {$regs[1]}<BR>".
  $file = str_replace($regs[0], "", $file); // voorkomt dat de comment nog een keer gevonden wordt
}

Acties:
  • 0 Henk 'm!

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 18:28

alienfruit

the alien you never expected

Waarom niet een extra functie aanmaken met de uitleg erbij? functienaam_comment() ofzo en dan dat aanroepen via call_user_function().

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
alienfruit schreef op donderdag 09 juni 2005 @ 15:58:
Waarom niet een extra functie aanmaken met de uitleg erbij? functienaam_comment() ofzo en dan dat aanroepen via call_user_function().
Daar heb ik ook aan gedacht; ook om elke _ding-functie een extra parameter erbij te geven:
PHP:
1
2
3
4
5
6
7
8
function foo_ding($comment=false) {
  if ($comment) {
    return 'dit is de beschrijving';
  }
  else {
    return 'functie output!';
  }
}

Maar het lijkt me in principe logischer de werking van een functie in het commentaar te zetten; daar staat immers ook alle andere info over die functie...

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Suepahfly
  • Registratie: Juni 2001
  • Laatst online: 17-09 17:05
Al eens gekeken naar PHPDoc
Is ongeveer het zefde als JavaDoc.

Het genereerd api documentatie uit php source files. Met een simpele editor haal de functies er uit die je niet aan je users wilt laten zien

Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Reveller schreef op donderdag 09 juni 2005 @ 16:15:
Maar het lijkt me in principe logischer de werking van een functie in het commentaar te zetten; daar staat immers ook alle andere info over die functie...
Daarbij hoort die functie geen twee totaal verschillende dingen uit te voeren. (Seperation of concerns..)

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
frickY schreef op donderdag 09 juni 2005 @ 14:30:
Lijkt me dat je gewoon met een eregi kunt matchen [...]
Ik heb nu de volgende code (in het bestand macro.php) maar krijg geen output. $file is een bestaand pad en elk commentaar bevat @user. Met mijn beperkte kennis van regex'en vraag ik mij af: leest de regex toch wel het commentaar boven elke functie?
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
 * @description Dit moet niet meegenomen worden 
 *   in de output van dingen_info
 * @user Deze functie doet mooie dingen.
 *   Hele mooie dingen!
 */
function foo_ding() {
  return 'foo!';
}

/**
 * @user Deze functie doet iets stoms.
 *   Iets heel erg stoms!
 * @version Versienummer moet niet in de output
 *   van dingen_info()
 */
function bar_ding() {
  return 'bar!';
}

function get_dingen() {
  $func = get_defined_functions();
  $func = $func['user'];
  
  foreach ($func as $val) {
    if (substr($val, -5, 5) == '_ding') {
      $dingen[] = $val;
    }
  }

  return $dingen;
}

function dingen_info($file) {
  $file = file_get_contents($file);
  while(eregi("@user([[:print:]]*)function [A-Z]*_ding()", $file, $regs)) {
    echo "Gevonden comment: {$regs[1]}<br>";
    $file = str_replace($regs[0], "", $file);
  } 
}

dingen_info('C:\Program Files\Apache2\htdocs\test\macro.php');

[ Voor 6% gewijzigd door Reveller op 09-06-2005 20:44 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
$file is de inhoud van het bestand, niet de bestandsnaam. Gebruik file_get_contents om de inhoud te verkrijgen.

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Stom van me; normaal gesproken zou ik dat ook gezien hebben - laatste week op school enzo...leerlingen die op het laatste moment nog repetities willen inhalen, werkstukken moeten inleveren, etc...vermoeiend hoor :)

Overigens is de output met de aanpassing nog steeds leeg. Ik ga de regex nog maar eens ontleden en kijken waar het evt. voud gaat. Als iemand intussen zou kunnen helpen, dan natuurlijk graag :)

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Om toch maar even iets te doen gehad te hebben:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
function dingen_info($file, $commentNames = array())
{
    //Strip newlines
    $file = str_replace(array("\n", "\r"), ' ', $file);

    // Find methods with PHPDoc-style comments:
    // /**
    //  *
    //  */
    $hasMatch = preg_match_all(
        ";
            /\*\*                   #Comment start
                (?P<Comment>.*?)    #Comment contents
            \*/                     #End of the comment
                \s*
            function\s+(?P<Function>[a-z0-9_]*_ding) #Function name, all 'to be matched' end with _ding!!!
        ;xim", 
        $file, 
        $matches, 
        PREG_SET_ORDER
    );

    if($hasMatch)
    {
        //iterate found methods
        foreach($matches as $functionMatch)
        {
            echo 'In de functie ', $functionMatch['Function'], ':<br/>';
            parse_comments($functionMatch['Comment'], $commentNames);
        }
    }
}

function parse_comments($comment, $commentNames = array())
{
    $hasMatch = preg_match_all(
        ';
            @(?P<Name>[^ ]+)    #tag name, format @<text><space>
            (?P<Content>[^@]+)  #tag contents
        ;x', 
        $comment, 
        $commentMatch
    );

    if($hasMatch)
    {
        foreach($commentMatch['Name'] as $Key => $Name)
        {
            if(in_array($Name, $commentNames))
            {
                // convert back to newlines
                echo preg_replace(';\s*\*\s+;', "\n", $commentMatch['Content'][$Key]);
                echo '<br/>';
            }
        }
    }
}

dingen_info(file_get_contents(__FILE__), array('user'));

[ Voor 11% gewijzigd door PrisonerOfPain op 09-06-2005 21:39 ]


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
PrisonerOfPain schreef op donderdag 09 juni 2005 @ 21:37:
Om toch maar even iets te doen gehad te hebben:
PHP:
1
function\s+(?P<Function>[a-z0-9_]*_ding) #Function name, all 'to be matched' end with _ding!!!
Wow! Dat werkt perfect - dank je, PrisonerOfPain :)

Ik heb nu zelf geprobeerd de regex aan te passen zodat ik hem ook kan gebruiken voor functies die beginnen met "ding_". Onderstaande oplossing werkt echter niet helemaal: als er in #file een functie ding_foo() staat, retourneert de regex "ding_f" in plaats van de hele functie naam. Ik snap niet waarom hij niet werkt - ik heb de hulp ingeroepen van de RegEx Coach, maar dat programma geeft bij deze regex een foutmelding dat '(?' niet gevolgd mag worden door 'P'?

PHP:
1
function\s+(?P<Function>ding_*[a-z0-9_]) #Function name, all 'to be matched' begin with ding_

[ Voor 7% gewijzigd door Reveller op 11-06-2005 00:30 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Waarom zet je dan ook ineens het sterretje achter ding_ in plaats van achter de character class [a-z0-9_] waar hij hoort? ;)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
PHP:
1
function\s+(?P<Function>ding_[a-z0-9_]*)

Zo werkt hij in ieder geval niet - alle andere functies (dus: die niet met ding_ beginnen) worden dan ook gematched :(

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
De 'fout' zat 'm inderdaad niet bij de * operator. Hij lag bij de . operator die iets teveel matchte. Oplossing:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
$hasMatch = preg_match_all(
    ";
        /\*+                                #Comment start
            (?P<Comment>([^\*][^/])*)       #Comment contents
        \*+/                                #End of the comment
        \s*
        function\s+(?P<Function>[a-z0-9_]*_comments) #Function name, all 'to be matched' end with _ding!!!
    ;xim", 
    $file, 
    $matches, 
    PREG_SET_ORDER
);


Werkt ook met prefixes

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Ook dat is niet de oplossing; van wat ik begrijp, zoek je hiermee naar een nieuwe comment start, maar dat gebeurt al in regel 3 (?). Onderstaande code retourneert niets, niet met prefix en met postfix functies (functie parse_comments en dingen_info aanroep even weg gelaten):
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
 * @user Deze functie doet iets stoms. Iets heel erg stoms!
 * @version V0.1...moet niet meegenomen worden in output
 */
function ding_bar()
{
  return 'bar!';
}

/**
 * @user Deze functie doet mooie dingen. Hele mooie dingen!
 * @description Blaat...moet niet meegenomen worden in output
 */
function foo_ding()
{
  return 'foo!';
}

/**
 * @description Versienummer moet niet in de output van dingen_info()
 * @user Deze functie doet iets stoms. Iets heel erg stoms!
 */
function bar_ding()
{
  return 'bar!';
}

function dingen_info($file, $commentNames = array())
{
  $file = str_replace(array("\n", "\r"), ' ', $file);

  $hasMatch = preg_match_all(
      ";
          /\*+                                #Comment start
              (?P<Comment>([^\*][^/])*)       #Comment contents
          \*+/                                #End of the comment
          \s*
          function\s+(?P<Function>[a-z0-9_]*_ding) # functions with _ding
      ;xim", 
      $file, 
      $matches, 
      PREG_SET_ORDER
  ); 

  if($hasMatch)
  {
    foreach($matches as $functionMatch)
    {
      echo 'In de functie ', $functionMatch['Function'], ':<br/>';
      parse_comments($functionMatch['Comment'], $commentNames);
    }
  }
}

[ Voor 6% gewijzigd door Reveller op 11-06-2005 12:42 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Ik heb hem gevonden:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
  $hasMatch = preg_match_all(
      ";
        /\*\*                   #Comment start
            (?P<Comment>.*?)    #Comment contents
        \*/                     #End of the comment
             \s*
        function\s+(?P<Function>ding_[a-z0-9_]+) # functions beginning with ding_
      ;xim", 
      $file, 
      $matches, 
      PREG_SET_ORDER
  );

Nu matcht hij elke functie die met ding_ begint en minstens 1 karakter achter de underscore heeft staan; een zware bevalling, maar dan heb je ook wat. Hopelijk komt het iemand nog eens van pas. Dank voor alle hulp!

[ Voor 162% gewijzigd door Reveller op 12-06-2005 13:34 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."

Pagina: 1