पूर्णता के लिए, यहां एनोटेशन का उपयोग करने के साथ-साथ PHP भाषा का विस्तार करने के लिए दोनों का एक उदाहरण उदाहरण है, सभी एक ही फ़ाइल में।
ये 'वास्तविक' एनोटेशन हैं, जिसका अर्थ है भाषा स्तर पर घोषित किया गया है, और टिप्पणियों में छिपी नहीं है। इन तरह 'जावा' स्टाइल एनोटेशन का उपयोग करने का लाभ यह है कि टिप्पणियों को अनदेखा करने वाले पार्सर्स द्वारा उन्हें अनदेखा नहीं किया जा सकता है।
शीर्ष भाग, __halt_compiler();
से पहले प्रोसेसर है, एक सरल विधि एनोटेशन के साथ PHP भाषा को विस्तारित करता है जो कैश विधि कॉल करता है।
नीचे की कक्षा एक विधि पर @cache
एनोटेशन का उपयोग करने का एक उदाहरण है।
(यह कोड सबसे अच्छा नीचे पढ़ा गया है)।
<?php
// parser states
const S_MODIFIER = 0; // public, protected, private, static, abstract, final
const S_FUNCTION = 1; // function name
const S_SIGSTART = 2; // (
const S_SIGEND = 3; //)
const S_BODYSTART = 4; // {
const S_BODY = 5; // ...}
function scan_method($tokens, $i)
{
$state = S_MODIFIER;
$depth = 0; # {}
$funcstart = $i;
$fnameidx;
$funcbodystart;
$funcbodyend;
$sig_start;
$sig_end;
$argnames=array();
$i--;
while (++$i < count($tokens))
{
$tok = $tokens[$i];
if ($tok[0] == T_WHITESPACE)
continue;
switch ($state)
{
case S_MODIFIER:
switch ($tok[0])
{
case T_PUBLIC:
case T_PRIVATE:
case T_PROTECTED:
case T_STATIC:
case T_FINAL:
case T_ABSTRACT: # todo: handle body-less functions below
break;
case T_FUNCTION:
$state=S_FUNCTION;
break;
default:
return false;
}
break;
case S_FUNCTION:
$fname = $tok[1];
$fnameidx = $i;
$state = S_SIGSTART;
break;
case S_SIGSTART:
if ($tok[1]=='(')
{
$sig_start = $i;
$state = S_SIGEND;
}
else return false;
case S_SIGEND:
if ($tok[1]==')')
{
$sig_end = $i;
$state = S_BODYSTART;
}
else if ($tok[0] == T_VARIABLE)
$argnames[]=$tok[1];
break;
case S_BODYSTART:
if ($tok[1] == '{')
{
$funcbodystart = $i;
$state = S_BODY;
}
else return false;
#break; # fallthrough: inc depth
case S_BODY:
if ($tok[1] == '{') $depth++;
else if ($tok[1] == '}')
if (--$depth == 0)
return (object) array(
'body_start' => $funcbodystart,
'body_end' => $i,
'func_start' => $funcstart,
'fnameidx' => $fnameidx,
'fname' => $fname,
'argnames' => $argnames,
'sig_start' => $sig_start,
'sig_end' => $sig_end,
);
break;
default: die("error - unknown state $state");
}
}
return false;
}
function fmt($tokens) {
return implode('', array_map(function($v){return $v[1];}, $tokens));
}
function process_annotation_cache($tokens, $i, $skip, $mi, &$instructions)
{
// prepare some strings
$args = join(', ', $mi->argnames);
$sig = fmt(array_slice($tokens, $mi->sig_start, $mi->sig_end - $mi->sig_start ));
$origf = fmt(array_slice($tokens, $mi->func_start, $mi->body_start - $mi->func_start));
// inject an instruction to rename the cached function
$instructions[] = array(
'action' => 'replace',
'trigger' => $i,
'arg' => $mi->sig_end -$i -1,
'tokens' => array(array("STR", "private function __cached_fn_$mi->fname$sig"))
);
// inject an instruction to insert the caching replacement function
$instructions[] = array(
'action' => 'inject',
'trigger' => $mi->body_end + 1,
'tokens' => array(array("STR", "
$origf
{
static \$cache = array();
\$key = join('#', func_get_args());
return isset(\$cache[\$key]) ? \$cache[\$key]: \$cache[\$key] = \$this->__cached_fn_$mi->fname($args);
}
")));
}
function process_tokens($tokens)
{
$newtokens=array();
$skip=0;
$instructions=array();
foreach ($tokens as $i=>$t)
{
// check for annotation
if ($t[1] == '@'
&& $tokens[$i+1][0]==T_STRING // annotation name
&& $tokens[$i+2][0]==T_WHITESPACE
&& false !== ($methodinfo = scan_method($tokens, $i+3))
)
{
$skip=3; // skip '@', name, whitespace
$ann_method = 'process_annotation_'.$tokens[$i+1][1];
if (function_exists($ann_method))
$ann_method($tokens, $i, $skip, $methodinfo, $instructions);
# else warn about unknown annotation
}
// process instructions to modify the code
if (!empty($instructions))
if ($instructions[0]['trigger'] == $i) // the token index to trigger at
{
$instr = array_shift($instructions);
switch ($instr['action'])
{
case 'replace': $skip = $instr['arg']; # fallthrough
case 'inject': $newtokens=array_merge($newtokens, $instr['tokens']);
break;
default:
echo "<code style='color:red'>unknown instruction '{$instr[1]}'</code>";
}
}
if ($skip) $skip--;
else $newtokens[]=$t;
}
return $newtokens;
}
// main functionality
$data = file_get_contents(__FILE__, null, null, __COMPILER_HALT_OFFSET__);
$tokens = array_slice(token_get_all("<"."?php ". $data), 1);
// make all tokens arrays for easier processing
$tokens = array_map(function($v) { return is_string($v) ? array("STR",$v) : $v;}, $tokens);
echo "<pre style='background-color:black;color:#ddd'>" . htmlentities(fmt($tokens)) . "</pre>";
// modify the tokens, processing annotations
$newtokens = process_tokens($tokens);
// format the new source code
$newcode = fmt($newtokens);
echo "<pre style='background-color:black;color:#ddd'>" . htmlentities($newcode) . "</pre>";
// execute modified code
eval($newcode);
// stop processing this php file so we can have data at the end
__halt_compiler();
class AnnotationExample {
@cache
private function foo($arg = 'default') {
echo "<b>(timeconsuming code)</b>";
return $arg . ": 1";
}
public function __construct() {
echo "<h1 style='color:red'>".get_class()."</h1>";
echo $this->foo("A")."<br/>";
echo $this->foo("A")."<br/>";
echo $this->foo()."<br/>";
echo $this->foo()."<br/>";
}
}
new AnnotationExample();
एक डि कंटेनर का उदाहरण (जो मूल रूप से जो भी कुछ भी नहीं एनोटेशन के साथ क्या करना है) के साथ रहते हुए, ऊपर दृष्टिकोण भी किसी भी निर्भरता इंजेक्शन लगाने का ख्याल रखना है, जो उपयोग करता है वर्ग कंस्ट्रक्टर्स संशोधित करने के लिए इस्तेमाल किया जा सकता घटकों के पूरी तरह से पारदर्शी। मूल्यांकन से पहले स्रोत कोड को संशोधित करने का दृष्टिकोण लगभग कस्टम जावा क्लासलोडर में 'बाइटकोड उपकरण' के बराबर है। (मैं AFAIK के बाद जावा का उल्लेख करता हूं, जहां एनोटेशन पहली बार पेश किए गए थे)।
इस विशेष उदाहरण की उपयोगिता यह है कि प्रत्येक विधि के लिए मैन्युअल रूप से कैशिंग कोड लिखने के बजाय, आप आसानी से कैश होने, दोहराए जाने वाले काम की मात्रा को कम करने और कोड को स्पष्ट करने के तरीके को चिह्नित कर सकते हैं। साथ ही, किसी भी एनोटेशन के प्रभाव रनटाइम पर चालू और बंद हो सकते हैं।
मुझे लगता है कि आपको शायद अधिक विशिष्ट होना चाहिए, मुझे लगता है। –
... या कम से कम एक ठोस उदाहरण से लिंक करें। आपके उत्तर से लिया गया [यहां] (http://stackoverflow.com/questions/3623355/php-annotation-library/3623493#3623493): http://code.google.com/p/addendum/wiki/ShortTutorialByExample – deceze
यदि मैंने पूछा कि एक ओआरएम क्या उपयोगी था, मुझे दस लाख प्रतिक्रियाएं मिलेंगी। मैं एनोटेशन के उदाहरण देखता हूं लेकिन इसमें डूब गया नहीं है। वास्तव में यह क्या अच्छा है? आलसी लोडिंग गतिशील कोडिंग डीबग करना मुश्किल है? –