perl - usos - programar aplicaciones web
¿Por qué tengo que usar un*en frente de una aplicación de archivo de lengua sencilla de Perl? (3)
El *
refiere a un "typeglob" de Perl , que es un oscuro detalle de implementación de Perl. Algún código Perl más viejo necesita referirse a manejadores de archivos usando typeglobs (ya que no había otra manera de hacerlo en ese momento). Un código más moderno puede usar referencias Filehandle en su lugar, que son más fáciles de trabajar.
El *
es análogo a $
o %
, se refiere a un tipo diferente de objeto conocido con el mismo nombre.
Desde la página de documentación de perldata
:
Perl usa un tipo interno llamado typeglob para contener una entrada de tabla de símbolos completa. El prefijo de tipo de un typeglob es *, porque representa todos los tipos. Esta solía ser la forma preferida de pasar matrices y hashes por referencia a una función, pero ahora que tenemos referencias reales, esto rara vez es necesario.
Al intentar hacer esto:
my $obj = new JavaScript::Minifier;
$obj->minify(*STDIN, *STDOUT);
// modified above line to
$obj->minify(*IP_HANDLE,*OP_HANDLE)
Lo anterior funciona si IP_HANDLE y OP_HANDLE son manejadores de archivo, pero todavía no puedo descifrar qué hace *
cuando se aplica a un identificador de archivo o cualquier otro tipo de datos.
Gracias,
Es el glob sigil. *FOO
refiere al glob llamado "FOO", al igual que $FOO
refiere al escalar llamado "FOO", y así sucesivamente. Los Globs son generalmente referencias de código o manejadores de archivos.
Necesita el sigilo presente para modificar un valor global, p *name_of_sub = sub{};
Ej. *name_of_sub = sub{};
, o para tomar su valor sin invocar una sintaxis especial, por ejemplo, llamar a un sub.
En los viejos tiempos malos antes de Perl v5.6, que introdujo manejadores de archivos léxicos -hace más de una década atrás- el paso de manejadores de archivos y directorios era incómodo. El código de su pregunta está escrito usando este estilo pasado de moda.
El nombre técnico de *STDIN
, por ejemplo, es un typeglob , explicado en la sección "Typeglobs and Filehandles" de perldata . Puede encontrar la manipulación de typeglobs para diversos fines en el código heredado. Tenga en cuenta que puede tomar typeglobs de variables globales solamente, nunca léxicos.
Pasar manejadores era un propósito común para tratar directamente con typeglobs, pero también había otros usos. Ver abajo para más detalles.
- Pasar filehandles a subs
- Ambigüedad sintáctica: string o filehandle
- Alias a través de la asignación de typeglob
- Localizar identificadores localizando typeglobs
- Mirando debajo del capó:
*foo{THING}
sintaxis de*foo{THING}
- Atando todo: ¡DWIM!
Pasar filehandles a subs
La documentación de perldata explica :
Typeglobs y Filehandles
Perl usa un tipo interno llamado typeglob para contener una entrada de tabla de símbolos completa. El prefijo de tipo de un typeglob es
*
porque representa todos los tipos. Esta solía ser la forma preferida de pasar matrices y hashes por referencia a una función, pero ahora que tenemos referencias reales, esto rara vez es necesario.[...]
Otro uso de typeglobs es pasar filehandles en una función o crear nuevos filehandles. Si necesita usar un typeglob para guardar un identificador de archivo, hágalo de esta manera:
$fh = *STDOUT;
o tal vez como una referencia real, como esta:
$fh = /*STDOUT;
Consulte perlsub para ver ejemplos de cómo usarlos como manejadores de archivos indirectos en las funciones.
La sección referenciada de perlsub está abajo.
Pasar entradas de tabla de símbolos (typeglobs)
ADVERTENCIA: El mecanismo descrito en esta sección fue originalmente la única forma de simular pass-by-reference en versiones anteriores de Perl. Si bien funciona bien en las versiones modernas, generalmente es más fácil trabajar con el nuevo mecanismo de referencia. Vea abajo.
A veces no desea pasar el valor de una matriz a una subrutina, sino el nombre de la misma, de modo que la subrutina pueda modificar la copia global de la misma en lugar de trabajar con una copia local. En Perl puede referirse a todos los objetos de un nombre en particular prefijando el nombre con una estrella:
*foo
. Esto a menudo se conoce como "typeglob", porque la estrella en el frente se puede considerar como una coincidencia comodín para todos los caracteres de prefijo divertidos en variables y subrutinas y tal.Cuando se evalúa, typeglob produce un valor escalar que representa todos los objetos de ese nombre, incluidos cualquier identificador de archivo, formato o subrutina. Cuando se le asigna, hace que el nombre mencionado se refiera a cualquier valor
*
que se le haya asignado. [...]
Tenga en cuenta que un typeglob solo puede tomarse en variables globales, no en léxicos. Presta atención a la advertencia anterior. Prefiere evitar esta técnica oscura.
Ambigüedad sintáctica: ¿string o filehandle?
Sin el *
sigil, una palabra clave es solo una cadena.
Las cuerdas simples a veces son suficientes, hower. Por ejemplo, el operador de print
permite
$ perl -le ''print { "STDOUT" } "Hiya!"''
Hiya!
$ perl -le ''$h="STDOUT"; print $h "Hiya!"''
Hiya!
$ perl -le ''print "STDOUT" +123''
123
Estos fallan con strict ''refs''
habilitados. El manual explica:
FILEHANDLE puede ser un nombre de variable escalar, en cuyo caso la variable contiene el nombre o una referencia al identificador de archivo, introduciendo así un nivel de direccionamiento indirecto.
En tu ejemplo, considera la ambigüedad sintáctica. Sin el *
sigil, podría querer decir cadenas
$ perl -MO=Deparse,-p prog.pl
use JavaScript::Minifier;
(my $obj = ''JavaScript::Minifier''->new);
$obj->minify(''IP_HANDLE'', ''OP_HANDLE'');
o tal vez una subllamada
$ perl -MO=Deparse,-p prog.pl
use JavaScript::Minifier;
sub OP_HANDLE {
1;
}
(my $obj = ''JavaScript::Minifier''->new);
$obj->minify(''IP_HANDLE'', OP_HANDLE());
o, por supuesto, un identificador de archivo. Tenga en cuenta en los ejemplos anteriores cómo la palabra clave JavaScript::Minifier
también se compila como una cadena simple.
Habilite el pragma strict
y todo se apaga de todos modos:
$ perl -Mstrict prog.pl Bareword "IP_HANDLE" not allowed while "strict subs" in use at prog.pl line 6. Bareword "OP_HANDLE" not allowed while "strict subs" in use at prog.pl line 6.
Alias a través de la asignación de typeglob
Un truco con typeglobs que es útil para las publicaciones de es
*ARGV = *DATA;
(Podría ser más preciso con *ARGV = *DATA{IO}
, pero eso es un poco quisquilloso).
Esto permite que el operador de diamante <>
lea desde el identificador de archivo DATA
, como en
#! /usr/bin/perl
*ARGV = *DATA; # for demo only; remove in production
while (<>) { print }
__DATA__
Hello
there
De esta forma, el programa y su entrada pueden estar en un solo archivo, y el código es más parecido a cómo se verá en la producción: simplemente elimine la asignación typeglob.
Localizar identificadores localizando typeglobs
Como se señaló en perlsub
Valores temporales a través de
local()
ADVERTENCIA: en general, debe usar
my
lugar delocal
, porque es más rápido y más seguro. Las excepciones a esto incluyen las variables de puntuación globales, los manejadores de archivos y formatos globales, y la manipulación directa de la tabla de símbolos de Perl.local
se usa principalmente cuando el valor actual de una variable debe ser visible para las subrutinas llamadas. [...]
puedes usar typeglobs para localizar filehandles:
$ cat prog.pl
#! /usr/bin/perl
sub foo {
local(*STDOUT);
open STDOUT, ">", "/dev/null" or die "$0: open: $!";
print "You can''t see me!/n";
}
print "Hello/n";
foo;
print "Good bye./n";
$ ./prog.pl
Hello
Good bye.
"Cuando todavía usar local()
" en perlsub tiene otro ejemplo.
2. Necesita crear un archivo local o un manejador de directorio o una función local.
Una función que necesita un identificador de archivo propio debe usar
local()
en un typeglob completo. Esto se puede usar para crear nuevas entradas de tabla de símbolos:
sub ioqueue { local (*READER, *WRITER); # not my! pipe (READER, WRITER) or die "pipe: $!"; return (*READER, *WRITER); } ($head, $tail) = ioqueue();
Para enfatizar, este estilo es pasado de moda. Prefiere evitar manejadores de archivos globales en código nuevo, pero es útil poder comprender la técnica en el código existente.
Mirando debajo del capó: *foo{THING}
sintaxis de *foo{THING}
Puede obtener las diferentes partes de un typeglob, como lo explica perlref :
Se puede crear una referencia utilizando una sintaxis especial, cariñosamente conocida como la sintaxis
*foo{THING}
.*foo{THING}
devuelve una referencia a la ranura THING en*foo
(que es la entrada de la tabla de símbolos que contiene todo lo que se conoce como foo).
$scalarref = *foo{SCALAR}; $arrayref = *ARGV{ARRAY}; $hashref = *ENV{HASH}; $coderef = *handler{CODE}; $ioref = *STDIN{IO}; $globref = *foo{GLOB}; $formatref = *foo{FORMAT};
Todos estos se explican por sí mismos a excepción de
*foo{IO}
. Devuelve el identificador de IO, que se utiliza para los identificadores de archivo (open
), los sockets (socket
ysocketpair
) y los identificadores de directorio (opendir
). Para compatibilidad con versiones anteriores de Perl,*foo{FILEHANDLE}
es un sinónimo de*foo{IO}
, aunque está en desuso a partir de 5.8.0. Si las advertencias de depreciación están en vigencia, advertirá sobre su uso.
*foo{THING}
undef
*foo{THING}
devuelveundef
si esa COSA en particular no se ha usado aún, excepto en el caso de escalares.*foo{SCALAR}
devuelve una referencia a un escalar anónimo si$foo
no se ha utilizado aún. Esto podría cambiar en una versión futura.
*foo{IO}
es una alternativa al*HANDLE
mecanismo dado en ["Typeglobs y Filehandles" en perldata] para pasar filehandles dentro o fuera de subrutinas, o almacenar en estructuras de datos más grandes. Su desventaja es que no creará una nueva Filehandle para usted. Su ventaja es que tiene menos riesgo de golpear más de lo que desea con una asignación typeglob. (Sin embargo, aún combina identificadores de archivos y directorios). Sin embargo, si asigna el valor entrante a un escalar en lugar de un typeglob como lo hacemos en los ejemplos a continuación, no hay riesgo de que eso suceda.
splutter(*STDOUT); # pass the whole glob splutter(*STDOUT{IO}); # pass both file and dir handles sub splutter { my $fh = shift; print $fh "her um well a hmmm/n"; } $rec = get_rec(*STDIN); # pass the whole glob $rec = get_rec(*STDIN{IO}); # pass both file and dir handles sub get_rec { my $fh = shift; return scalar <$fh>; }
Atando todo: ¡DWIM!
El contexto es clave con Perl. En su ejemplo, aunque la sintaxis puede ser ambigua, la intención no es: incluso si los parámetros son cadenas, esas cadenas están claramente destinadas a nombrar Filehandles.
Así que considere todos los casos que necesite manejar minify
:
- sin palabras
- typeglob desnudo
- referencia a typeglob
- Filehandle en escalar
Por ejemplo:
#! /usr/bin/perl
use warnings;
use strict;
*IP_HANDLE = *DATA;
open OP_HANDLE, ">&STDOUT";
open my $fh, ">&STDOUT";
my $offset = tell DATA;
use JavaScript::Minifier;
my $obj = JavaScript::Minifier->new;
$obj->minify(*IP_HANDLE, "OP_HANDLE");
seek DATA, $offset, 0 or die "$0: seek: $!";
$obj->minify(/*IP_HANDLE, $fh);
__DATA__
Ahoy there
matey!
Como autor de la biblioteca, ser servicial puede ser útil. Para ilustrarlo, el siguiente apéndice de JavaScript :: Minifier comprende las formas anticuadas y modernas de pasar identificadores de archivo.
package JavaScript::Minifier;
use warnings;
use strict;
sub new { bless {} => shift }
sub minify {
my($self,$in,$out) = @_;
for ($in, $out) {
no strict ''refs'';
next if ref($_) || ref(/$_) eq "GLOB";
my $pkg = caller;
$_ = *{ $pkg . "::" . $_ }{IO};
}
while (<$in>) { print $out $_ }
}
1;
Salida:
$ ./prog.pl Name "main::OP_HANDLE" used only once: possible typo at ./prog.pl line 7. Ahoy there matey! Ahoy there matey!