Attributes: look inside
This is a continuation of the Introduction to Attributes article . If you are not familiar with the idea of attributes and their syntax, I advise you to start with it. Well, this article discusses how attributes are arranged from the inside, how to handle them, and what problems may arise.
When Perl encounters an attribute during compilation, it tries to call one of the view handlers in the current class
I repeat: these calls are made right at compile time (at the BEGIN stage), or rather, right after perl documents the closing brace ( fair UPD from xames : not all view handles are
Similarly, if you want to get a list of attributes of a function / variable and call the get function from the attributes module for this, the handle is called
Actually, all the features of working with attributes at a low level can be found in perldoc attributes . By the way, for those who find this implementation crooked, there is an important note: " The mechanisms described here are still experimental. Do not rely on the current implementation". Well, there is nothing more permanent than experimental mechanisms :-)
Obviously, picking attributes with the help of the aforementioned handlers is not very pleasant. Thank God, a module appeared in the delivery of the same Perl 5.6
So, in order to use the attribute
If we want to pass additional information to the handler, you can do this for example like this:
In this case, the handler will receive an array with the values of
Other fun features
It is worth noting that most CPAN modules that use attributes rely on the module
The CHECK phase is not in vain chosen
In fact, attributes allow you to attach additional features to the usual components of the program. The interest of these features is that they are not actually visible in the code. This is somewhat similar
Guts
When Perl encounters an attribute during compilation, it tries to call one of the view handlers in the current class
MODIFY_SCALAR_ATTRIBUTES
, MODIFY_CODE_ATTRIBUTES
etc. - depending on the type of data marked with the attribute, something like this: __PACKAGE__->MODIFY_CODE_ATTRIBUTES(\&mySub, 'myAttribute1', 'myAttribute2');
I repeat: these calls are made right at compile time (at the BEGIN stage), or rather, right after perl documents the closing brace ( fair UPD from xames : not all view handles are
MODIFY_*_ATTRIBUTES
executed at the BEGIN stage, in particular, they are MODIFY_SCALAR_ATTRIBUTES
executed at the initialization stage of the variable ( my $tmp: attr = 0;
)) Since there may be several attributes, and no one has canceled the inheritance, it is considered good practice to scan the list inside the handler, select from it those attributes that can be processed, and give what remains to the superclass to tear to pieces. Similarly, if you want to get a list of attributes of a function / variable and call the get function from the attributes module for this, the handle is called
FETCH_SCALAR_ATTRIBUTES
(well, or FETCH_CODE_ATTRIBUTES
- I think you already understand). Actually, all the features of working with attributes at a low level can be found in perldoc attributes . By the way, for those who find this implementation crooked, there is an important note: " The mechanisms described here are still experimental. Do not rely on the current implementation". Well, there is nothing more permanent than experimental mechanisms :-)
Recipe for happiness
Obviously, picking attributes with the help of the aforementioned handlers is not very pleasant. Thank God, a module appeared in the delivery of the same Perl 5.6
Attribute::Handlers
, which greatly simplifies the writing of handlers for attributes and introduces additional interesting features - attributes can have parameters and are processed not only during the BEGIN stage, but also during CHECK, INIT, END. By the way, this module works again with the help of attributes. So, in order to use the attribute
myAttribute
to mark functions, it is enough to write the following code:
Handler - methoduse Attribute::Handlers;
sub myAttribute : ATTR(CODE) {
my ($package, $symbol, $referent, $attr, $data, $phase, $filename, $linenum) = @_;
....
}
myAttribute
- will be called for the marked function in much the same way as the handlers from the previous examples. Significantly more parameters are passed to it: in addition to the link to the function and the attribute name, there may also be a link to a symbol table element (GLOB), phase name BEGIN / CHECK / INIT / END, additional attribute parameters, an indication of the file name and line number. By default, the handler is launched during the CHECK compilation stage, when everything that can be already loaded and digested. If we want to pass additional information to the handler, you can do this for example like this:
sub mySub : myAttribute(p1,p2) {:}
In this case, the handler will receive an array with the values of
p1
and in the variable $ data p2
. Other fun features
Attribute::Handlers
include an alternative interface to the function.tie
, which in itself is a rather interesting example of the use of attributes. It does not make much sense to dwell on it; everything is extremely clear from the documentation. It is worth noting that most CPAN modules that use attributes rely on the module
Attribute::Handlers
. However, it will not always help. Moreover, do not hope that everything is as smooth and beautiful as it seems :)Rake
The CHECK phase is not in vain chosen
Attribute::Handlers
as default. At this phase, the interpreter has already finished processing the code and placed the functions and everything else in the symbol table, so now it is technically possible to get a link to the corresponding GLOB and play over it - for example, to replace a function. You cannot do this in the BEGIN phase - the GLOB is not yet full, and the attribute will not be passed to the handler. And here the fun begins. If you are developing for mod_perl, all this does not apply to you - you do not have the CHECK phase. According to perldoc perlmod , inside callseval
and under mod_perl the compilation stages CHECK and INIT do not work, there is only BEGIN and UNITCHECK. Not everything is going smoothly with UNITCHECK either - globally this phase is not intercepted, only at the level of the corresponding module. I could not find a module that would solve this problem and make it possible to get to GLOB under mod_perl as trivially as it can be done in a regular script. It would be possible to add at the level the Attribute::Handlers
ability to enter your own triggers to launch handlers and pull them manually - but the module is written so that you can immediately forget about such patches. I was able to solve this problem by actually introducing an additional restriction when writing code - I had to abandon it require
when loading classes in favoruse
. As a result, the work is done in two steps - first, at the BEGIN stage, a list of functions marked with the attribute I need is collected, and after the method import
is called , the main work is done. If someone offers a more humane way, I will be glad.Conclusion
In fact, attributes allow you to attach additional features to the usual components of the program. The interest of these features is that they are not actually visible in the code. This is somewhat similar
tie
- you perform elementary actions on the simplest data structures, behind which non-trivial processors are actually hidden. If you need some kind of universal mechanism, but you do not want the features of its implementation to be visible in the code, look in the direction of attributes.