ethnaAdminにphpdocの解析を追加

結局コメントも取れないと意味ないねってことで、コメントの解析。PEARを見たところすぐに使えそうなツールはないんですよね(涙目)

PHP_Parser_DocblockParserってのがあるんですが、docblockってPECL使っているし。。。

今回は正規表現でがしがし持ってきています。token_get_all()でトークンに分割して、T_DOC_COMMENTだった場合には正規表現で抜き出し。次に続くトークンがclassとかfunctionの場合には解析したDOCをくっつけています。

  action-form: 
    name: /Contact/Initialize
    realname: www/app/action/Contact/Initialize.php
    extends: Neko_Form_ContactInput
    form: 
      type: 
        type: VAR_TYPE_STRING
        form_type: FORM_TYPE_HIDDEN
        name: お問い合わせ種別
      contact_info: 
        type: VAR_TYPE_STRING
        form_type: FORM_TYPE_TEXT
        required: true
        mbmax: 50
        name: お名前(漢字)
      contact_info_kana: 
        type: VAR_TYPE_STRING
        form_type: FORM_TYPE_TEXT
        required: true
        custom: checkHiragana
        mbmax: 50
        name: お名前(ふりがな)
    phpdoc: 
      file: 
        items: 
          - 
            name: author
            body: {$author}
          - 
            name: package
            body: Neko
          - 
            name: version
            body: |
              $Id: skel.action.php,v 1.10 2006/11/06 14:31:24 cocoitiban Exp $
        body: Contact/Initialize.php
      class: 
        - 
          name: Neko_Form_ContactInitialize
          extends: Neko_Form_ContactInput
          doc: 
            items: 
              - 
                name: author
                body: {$author}
              - 
                name: access
                body: public
              - 
                name: package
                body: Neko
            body: contact_initializeフォームの実装
        - 
          name: Neko_Action_ContactInitialize
          extends: Neko_ActionClass
          doc: 
            items: 
              - 
                name: author
                body: {$author}
              - 
                name: access
                body: public
              - 
                name: package
                body: Neko
            body: >
              contact_initializeアクションの実装
      function: 
        - 
          name: prepare
          doc: 
            items: 
              - 
                name: access
                body: public
              - 
                name: return
                body: >
                  string     
                  遷移名(正常終了ならnull,
                  処理終了ならfalse)
            body: >
              contact_initializeアクションの前処理
        - 
          name: perform
          doc: 
            items: 
              - 
                name: access
                body: public
              - 
                name: return
                body: string  遷移名
            body: >
              contact_initializeアクションの実装
      return: 
        - 
          name: contact_input
          function: perform
          doc: 

こんな感じで取得してきています。

<?php
//-----------------------------------------------------------------------------
// アクション検索
//-----------------------------------------------------------------------------
function find_comments($str){
	$tokens = token_get_all($str);

	$doc = null;
	$system = false;
	$data = array();
	$mode = '';

	foreach ($tokens as $token){
		if (is_array($token)){
			switch ($token[0]){
				case T_COMMENT:
					break;

				case T_DOC_COMMENT:
					$doc = doc_block($token[1]);
					if( $system == false ){
						// 一番最初はファイルの説明
						$data['file'] = $doc;
						$system = true;
						$doc = null;
					}
					break;

				default:
					switch( $token[1] ){
						case 'class':
							$mode = 'class';
							break;

						case 'extends':
							if( $mode == 'class' ){
								$mode = 'extends';
							}
							break;

						case 'function':
							$mode = 'function';
							break;

						case 'return':
							$mode = 'return';
							break;

						default:
							if( trim( $token[1] ) ){
								if( $mode == 'class' ){
									$class_name = $token[1];
								} elseif( $mode == 'extends' ){
									$data['class'][] = array( 'name' => $class_name, 'extends' => $token[1], 'doc' => $doc );
									$doc = null;
									$mode = '';
									$class_name = '';
								} elseif( $mode == 'function' ){
									$data['function'][] = array( 'name' => $token[1], 'doc' => $doc );
									$doc = null;
									$mode = '';
									$function = $token[1];
								} elseif( $mode == 'return' ){
									if( strtolower( $token[1] ) != 'null' ){
										$token[1] = str_replace( "'", '', $token[1] );
										$token[1] = str_replace( '"', '', $token[1] );
										$data['return'][] = array( 'name' => $token[1], 'function' => $function, 'doc' => $doc );
									}
									$doc = null;
									$mode = '';
								} else {
									$doc = null;
									$mode = '';
								}
							}
					}
					break;
			}
		} else {
		}
	}

	return $data;
}

//-----------------------------------------------------------------------------
// phpdoc解説
//-----------------------------------------------------------------------------
function doc_block($str){
	$doc = array();

	// コメントの閉じを削除
	$str = preg_replace('/\*\//', '', $str );

	// パラメータ
	$doc['items'] = array();
	preg_match_all('/\*[ ]+@(.*)/', $str, $match);
	foreach($match[1] as $item){
		preg_match('/(.*?)[ ]+(.*)/', $item, $match2);

		$item = array();
		$item['name'] = $match2[1];
		$item['body'] = $match2[2];
		$doc['items'][] = $item;
	}

	// ボディ取得
	$str = preg_replace('/\*[ ]+@(.*)/', '', $str );
	preg_match_all('/\*[ ]+(.*)/', $str, $match);
	$body = array();
	foreach($match[1] as $item){
		if( trim( $item ) ){
			$body[] = trim( $item );
		}
	}
	if( $body ){
		$doc['body'] = implode( "\n", $body );
	}

	return $doc;
}

抜き出し部分です。THE力技〜!
てかphpdoc書いてないじゃん(笑)