⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch13_16.htm

📁 By Tom Christiansen and Nathan Torkington ISBN 1-56592-243-3 First Edition, published August 1998
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<HTML><HEAD><TITLE>Recipe 13.15. Creating Magic Variables with tie (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen &amp; Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly &amp; Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:42:35Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-243-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch13_01.htm"TITLE="13. Classes, Objects, and Ties"><LINKREL="prev"HREF="ch13_15.htm"TITLE="13.14. Overloading Operators"><LINKREL="next"HREF="ch14_01.htm"TITLE="14. Database Access"></HEAD><BODYBGCOLOR="#FFFFFF"><img alt="Book Home" border="0" src="gifs/smbanner.gif" usemap="#banner-map" /><map name="banner-map"><area shape="rect" coords="1,-2,616,66" href="index.htm" alt="Perl Cookbook"><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map><div class="navbar"><p><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch13_15.htm"TITLE="13.14. Overloading Operators"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 13.14. Overloading Operators"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch13_01.htm"TITLE="13. Classes, Objects, and Ties"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="chapter"HREF="ch14_01.htm"TITLE="14. Database Access"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 14. Database Access"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch13-24376">13.15. Creating Magic Variables with tie</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-pgfId-2257">Problem<ACLASS="indexterm"NAME="ch13-idx-1000004677-0"></A><ACLASS="indexterm"NAME="ch13-idx-1000004677-1"></A><ACLASS="indexterm"NAME="ch13-idx-1000004677-2"></A><ACLASS="indexterm"NAME="ch13-idx-1000004677-3"></A><ACLASS="indexterm"NAME="ch13-idx-1000004677-4"></A><ACLASS="indexterm"NAME="ch13-idx-1000004677-5"></A></A></H3><PCLASS="para">You want to add special processing to a variable or handle.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-pgfId-2263">Solution</A></H3><PCLASS="para">Use the <CODECLASS="literal">tie</CODE> function to give your ordinary variables object hooks.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-pgfId-2269">Discussion</A></H3><PCLASS="para">Anyone who's ever used a DBM file under Perl has already used tied objects. Perhaps the most excellent way of using objects is such that the user never notices them. With <CODECLASS="literal">tie</CODE>, you can bind a variable or handle to a class, after which all access to the tied variable or handle is transparently intercepted by specially named object methods.</P><PCLASS="para">The most important <CODECLASS="literal">tie</CODE> methods are <ACLASS="indexterm"NAME="ch13-idx-1000004678-0"></A>FETCH to intercept read access, <ACLASS="indexterm"NAME="ch13-idx-1000004679-0"></A>STORE to intercept write access, and the constructor, which is one of <ACLASS="indexterm"NAME="ch13-idx-1000004680-0"></A>TIESCALAR, TIEARRAY, TIEHASH, or TIEHANDLE.</P><TABLECLASS="informaltable"BORDER="1"CELLPADDING="3"><THEADCLASS="thead"><TRCLASS="row"VALIGN="TOP"><THCLASS="entry"ALIGN="LEFT"ROWSPAN="1"COLSPAN="1"><PCLASS="para">User Code</P></TH><THCLASS="entry"ALIGN="LEFT"ROWSPAN="1"COLSPAN="1"><PCLASS="para">Executed Code</P></TH></TR></THEAD><TBODYCLASS="tbody"><TRCLASS="row"VALIGN="TOP"><TDCLASS="entry"ROWSPAN="1"COLSPAN="1">&#13;<PRECLASS="programlisting">tie $s, &quot;SomeClass&quot;</PRE></TD><TDCLASS="entry"ROWSPAN="1"COLSPAN="1">&#13;<PRECLASS="programlisting">SomeClass-&gt;<CODECLASS="literal">TIESCALAR()</CODE></PRE></TD></TR><TRCLASS="row"VALIGN="TOP"><TDCLASS="entry"ROWSPAN="1"COLSPAN="1">&#13;<PRECLASS="programlisting">$p = $s</PRE></TD><TDCLASS="entry"ROWSPAN="1"COLSPAN="1">&#13;<PRECLASS="programlisting">$p = $obj-&gt;<CODECLASS="literal">FETCH()</CODE></PRE></TD></TR><TRCLASS="row"VALIGN="TOP"><TDCLASS="entry"ROWSPAN="1"COLSPAN="1">&#13;<PRECLASS="programlisting">$s = 10</PRE></TD><TDCLASS="entry"ROWSPAN="1"COLSPAN="1">&#13;<PRECLASS="programlisting">$obj-&gt;STORE(10)</PRE></TD></TR></TBODY></TABLE><PCLASS="para">Where did that <CODECLASS="literal">$obj</CODE> come from? The <CODECLASS="literal">tie</CODE> triggers a call to the class's TIESCALAR constructor method. Perl squirrels away the object returned and surreptitiously uses it for later access.</P><PCLASS="para">Here's a simple example of a <CODECLASS="literal">tie</CODE> class that implements a value ring. Every time the variable is read from, the next value on the ring is displayed. When it's written to, a new value is pushed on the ring. Here's an example:</P><PRECLASS="programlisting">#!/usr/bin/perl# demo_valuering - show tie classuse ValueRing;tie $color, 'ValueRing', qw(red blue);print &quot;$color $color $color $color $color $color\n&quot;;<BCLASS="emphasis.bold">red blue red blue red blue</B>$color = 'green';print &quot;$color $color $color $color $color $color\n&quot;;<BCLASS="emphasis.bold">green red blue green red blue</B></PRE><PCLASS="para">The simple implementation is shown in <ACLASS="xref"HREF="ch13_16.htm#ch13-35467"TITLE="ValueRing">Example 13.3</A>.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch13-35467">Example 13.3: ValueRing</A></H4><PRECLASS="programlisting">package ValueRing;# this is the constructor for scalar tiessub TIESCALAR {    my ($class, @values) = @_;    bless  \@values, $class;    return \@values;} # this intercepts read accessessub FETCH {    my $self = shift;    push(@$self, shift(@$self));    return $self-&gt;[-1];} # this intercepts write accessessub STORE {    my ($self, $value) = @_;    unshift @$self, $value;    return $value;} 1;</PRE></DIV><PCLASS="para">This example might not be compelling, but it illustrates how easy it is to write ties of arbitrary complexity. To the user, <CODECLASS="literal">$color</CODE> is just a plain old variable, not an object. All the magic is hidden beneath the tie. You don't have to use a scalar reference just because you're tying a scalar. Here we've used an array reference, but you can use anything you'd like. Usually a hash reference will be used irrespective of what's being tied to because it's the most flexible object representation.</P><PCLASS="para">For arrays and hashes, more elaborate operations are possible. Tied handles didn't appear until the 5.004 release, and prior to 5.005 use of tied arrays was somewhat limited, but tied hashes have always been richly supported. Because so many object methods are needed to fully support tied hashes, most users choose to inherit from the standard Tie::Hash module, which provides default methods for these. <ACLASS="indexterm"NAME="ch13-idx-1000004707-0"></A></P><PCLASS="para">Following are numerous examples of interesting uses of ties.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-chap13_tie_0">Tie Example: Outlaw $_</A></H3><PCLASS="para"><ACLASS="indexterm"NAME="ch13-idx-1000004686-0"></A><ACLASS="indexterm"NAME="ch13-idx-1000004686-1"></A>This curious tie class is used to outlaw unlocalized uses of the implicit variable, <CODECLASS="literal">$_</CODE>. Instead of pulling it in with <CODECLASS="literal">use</CODE>, which implicitly invokes the class's <CODECLASS="literal">import ( )</CODE> method, this one should be loaded with <CODECLASS="literal">no</CODE> to call the seldom-used <CODECLASS="literal">unimport ( )</CODE> method. The user says:</P><PRECLASS="programlisting">no UnderScore;</PRE><PCLASS="para">Then, all uses of the unlocalized global <CODECLASS="literal">$_</CODE> will raise an exception.</P><PCLASS="para">Here's a little test suite for the module.</P><PRECLASS="programlisting">#!/usr/bin/perl# <ACLASS="indexterm"NAME="ch13-idx-1000006758-0"></A>nounder_demo - show how to ban $_ from your programno UnderScore;@tests = (    &quot;Assignment&quot;  =&gt; sub { $_ = &quot;Bad&quot; },    &quot;Reading&quot;     =&gt; sub { print },     &quot;Matching&quot;    =&gt; sub { $x = /badness/ },    &quot;Chop&quot;        =&gt; sub { chop },    &quot;Filetest&quot;    =&gt; sub { -x },     &quot;Nesting&quot;     =&gt; sub { for (1..3) { print } },);while ( ($name, $code) = splice(@tests, 0, 2) ) {    print &quot;Testing $name: &quot;;    eval { &amp;$code };    print $@ ? &quot;detected&quot; : &quot;missed!&quot;;    print &quot;\n&quot;;} </PRE><PCLASS="para">The result is the following:</P><PRECLASS="programlisting"><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Testing Assignment: detected</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Testing Reading: detected</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Testing Matching: detected</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Testing Chop: detected</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Testing Filetest: detected</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Testing Nesting: 123missed!</I></CODE></B></CODE></PRE><PCLASS="para">The reason the last one was missed is that it was properly localized by the <CODECLASS="literal">for</CODE> loop, so it was considered safe.</P><PCLASS="para">The UnderScore module itself is shown in <ACLASS="xref"HREF="ch13_16.htm#ch13-32163"TITLE="UnderScore (continued)">Example 13.4</A>. Notice how small it is. The module itself does the <CODECLASS="literal">tie</CODE> in its initialization code.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch13-32163">Example 13.4: UnderScore (continued)</A></H4><PRECLASS="programlisting">package UnderScore;use Carp;sub TIESCALAR {    my $class = shift;    my $dummy;    return bless \$dummy =&gt; $class;} sub FETCH { croak &quot;Read access to \$_ forbidden&quot;  } sub STORE { croak &quot;Write access to \$_ forbidden&quot; } sub unimport { tie($_, __PACKAGE__) }sub import { untie $_ } tie($_, __PACKAGE__) unless tied $_;1;</PRE></DIV><PCLASS="para">You can't usefully mix calls to <CODECLASS="literal">use</CODE> and <CODECLASS="literal">no</CODE> for this class in your program, because they all happen at compile time, not run time. To renege and let yourself use <CODECLASS="literal">$_</CODE> again, <CODECLASS="literal">local</CODE>ize it.<ACLASS="indexterm"NAME="ch13-idx-1000004688-0"></A><ACLASS="indexterm"NAME="ch13-idx-1000004688-1"></A></P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -