note
xdg
<p>It's part of the [mod://attributes] mechanism. It's automatically called to handle the attributes of an appropriate type:
</p>
<blockquote><i>
<p> MODIFY_*type*_ATTRIBUTES</p>
<p>
This method is called with two fixed arguments, followed by the list
of attributes from the relevant declaration. The two fixed arguments
are the relevant package name and a reference to the declared
subroutine or variable. The expected return value is a list of
attributes which were not recognized by this handler. Note that this
allows for a derived class to delegate a call to its base class, and
then only examine the attributes which the base class didn't already
handle for it.
</p>
<p>
The call to this method is currently made *during* the processing of
the declaration. In particular, this means that a subroutine
reference will probably be for an undefined subroutine, even if this
declaration is actually part of the definition.
</p>
</i></blockquote>
<p>
You might also want to browse the source of [mod://Attribute::Handlers] for examples of how they get used.
</p>
<p><b>Updated: expanded answer...</b></p>
<p>[mod://attributes] came into being around Perl 5.6. When Perl sees an attribute (see [doc://perlsub] for the syntax), the attribute gets expanded into a call to the <code>attributes</code> module.</p>
<code>
my %name : ATTR;
# becomes
use attributes ();
my %name;
attributes::->import(__PACKAGE__, \%name, 'ATTR');
</code>
<p><code>attributes</code> in turn, looks for a <code>MODIFY_*_ATTRIBUTES</code> in the current package or the <code>@ISA</code> array and calls it to handle the attribute. If that function returns any attributes, those are "unhandled" attributes and the <code>import</code> croaks with an error.</p>
<p><code>MODIFY_*_ATTRIBUTES</code> receives the package name, a reference to the item attributed, and a list of attributes attached. E.g. in Class::Std:</p>
<code>
sub MODIFY_HASH_ATTRIBUTES {
my ($package, $referent, @attrs) = @_;
...
</code>
<p>The rest of that routine checks for an "ATTR" attribute, extracts any information passed along with it, like defaults, and installs the accessors as "usual". For example:</p>
<code>
if ($getter = _extract_get($config)) {
no strict 'refs';
*{$package.'::get_'.$getter} = sub {
return $referent->{ID($_[0])};
}
}
</code>
<p>The only "magic" here is the way that Perl automatically expands the ":ATTR" into a call to the <code>attributes</code> module. After that, it's just normal function calls between modules.</p>
<p>CAVEAT: this all happens at compile time -- so it's like a BEGIN block and certain things aren't yet set up. This is why in <code>MODIFY_CODE_ATTRIBUTES</code>, the name and reference of the method are just pushed onto a data structure, and the actual handling of the attribute occurs later in the CHECK block, after the method has been compiled.</p>
<p>(This is why anything build with Class::Std won't work with mod_perl, which has no CHECK phase. You can see an approach which will work in my own experimental [mod://Object::LocalVars], which requires the module using it to make an explicit function call to <code>give_methods</code> which gets run after its compilation when the module is first loaded in what is effectively a BEGIN phase at that point.)</p>
<div class="pmsig"><div class="pmsig-268515">
<p>-xdg</p>
<p><small><i>Code written by xdg and posted on PerlMonks is <a href="http://creativecommons.org/licenses/publicdomain">public domain</a>. It is provided <b>as is</b> with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.</i></small></p>
</div></div>
499997
499997