предупреждения
СОДЕРЖАНИЕ
ИМЯ
warnings - Perl-прагма для управления необязательными предупреждениями
СИНОПСИС
use warnings;
no warnings;
use warnings "all";
no warnings "uninitialized";
# or equivalent to those last two ...
use warnings qw(all -uninitialized);
use warnings::register;
if (warnings::enabled()) {
warnings::warn("some warning");
}
if (warnings::enabled("void")) {
warnings::warn("void", "some warning");
}
if (warnings::enabled($object)) {
warnings::warn($object, "some warning");
}
warnings::warnif("some warning");
warnings::warnif("void", "some warning");
warnings::warnif($object, "some warning"); ОПИСАНИЕ
Pragma warnings даёт контроль над тем, какие предупреждения включены в каких частях программы Perl. Это более гибкая альтернатива как для флага командной строки -w, так и для эквивалентной переменной Perl, $^W.
Эта прагма работает так же, как и прагма strict. Это означает, что область действия прагмы предупреждений ограничена содержащим блоком. Это также означает, что настройка прагмы не будет просачиваться в другие файлы (через use, require или do). Это позволяет авторам независимо определять степень проверки предупреждений, которые будут применяться к их модулю.
По умолчанию необязательные предупреждения отключены, поэтому любой устаревший код, который не пытается управлять предупреждениями, будет работать без изменений.
Все предупреждения включены в блоке, либо так:
use warnings;
use warnings 'all'; Аналогично, все предупреждения отключаются в блоке, либо так:
no warnings;
no warnings 'all'; Например, рассмотрите код ниже:
use warnings;
my @x;
{
no warnings;
my $y = @x[0];
}
my $z = @x[0]; В содержащем блоке предупреждения включены, но в внутреннем блоке они отключены. В этом случае это означает, что присвоение скаляру $z сработает предупреждение "Scalar value @x[0] better written as $x[0]", но присвоение скаляру $y — нет.
Предупреждения по умолчанию и необязательные предупреждения
Перед введением лексических предупреждений, в Perl были два класса предупреждений: обязательные и необязательные.
Как следует из названия, если ваш код вызывал обязательное предупреждение, вы получали предупреждение, хотите вы этого или нет. Например, код ниже всегда будет генерировать предупреждение "isn't numeric" о "2:".
my $x = "2:" + 3; С появлением лексических предупреждений, обязательные предупреждения теперь стали предупреждениями по умолчанию. Разница в том, что, хотя ранее обязательные предупреждения по умолчанию всё ещё включены, их можно затем включать или выключать с помощью лексической прагмы предупреждений. Например, в коде ниже предупреждение "isn't numeric" будет сообщено только для переменной $x.
my $x = "2:" + 3;
no warnings;
my $y = "2:" + 3; Обратите внимание, что ни флаг -w, ни $^W не могут использоваться для отключения/включения предупреждений по умолчанию. В этом случае они всё ещё обязательны.
«Предупреждения с отрицанием»
Для удобства, вы можете (с версии Perl 5.34) передавать аргументы в метод import() как положительно, так и отрицательно. Отрицательные предупреждения — это те, у которых перед их именами стоит знак -; положительные предупреждения — всё остальное. Это позволяет вам включить некоторые предупреждения и отключить другие в одной команде. Итак, предположим, что вы уже включили кучу предупреждений, но хотите немного их подкорректировать в некотором блоке, вы можете сделать это так:
{
use warnings qw(uninitialized -redefine);
...
} что эквивалентно:
{
use warnings qw(uninitialized);
no warnings qw(redefine);
...
} Список аргументов обрабатывается в том порядке, в котором вы его указываете. Например, если вы не хотите получать предупреждения об использовании экспериментальных функций, кроме somefeature, которое вам действительно не нравится, вы можете сказать так:
use warnings qw(all -experimental experimental::somefeature); что эквивалентно:
use warnings 'all';
no warnings 'experimental';
use warnings 'experimental::somefeature';
Что не так с -w и $^W
Несмотря на свою полезность, главная проблема использования -w в командной строке для включения предупреждений заключается в том, что это «всё или ничего». Рассмотрим типичный сценарий написания программы Perl. Части кода вы напишете сами, но очень вероятно, что вы будете использовать готовые Perl-модули. Если в этом случае вы используете флаг -w, вы включаете предупреждения в фрагментах кода, которые вы не написали.
Аналогично, использование $^W для отключения или включения блоков кода принципиально ошибочно. Например, скажем, вы хотите отключить предупреждения в блоке кода. Вы можете ожидать, что этого будет достаточно, чтобы сделать эту работу:
{
local ($^W) = 0;
my $x =+ 2;
my $y; chop $y;
} При выполнении этого кода с флагом -w будет выведено предупреждение для строки $x: "Reversed += operator".
Проблема в том, что в Perl есть предупреждения как на этапе компиляции, так и на этапе выполнения. Для отключения предупреждений на этапе компиляции необходимо переписать код так:
{
BEGIN { $^W = 0 }
my $x =+ 2;
my $y; chop $y;
} И обратите внимание, что в отличие от первого примера, это навсегда установит $^W, так как оно не может выполняться как во время компиляции, так и быть локализовано в блоке выполнения.
Другая большая проблема с $^W заключается в том, как вы можете непреднамеренно изменить настройку предупреждения в неожиданных местах вашего кода. Например, при выполнении кода ниже (без флага -w) второй вызов doit вызовет предупреждение "Use of uninitialized value", в то время как первый — нет.
sub doit
{
my $y; chop $y;
}
doit();
{
local ($^W) = 1;
doit()
} Это следствие того, что $^W динамически сфокусировано.
Лексические предупреждения позволяют обойти эти ограничения, предоставляя более тонкий контроль над тем, где можно или нельзя вызывать предупреждения.
Управление предупреждениями с командной строки
Существует три флага командной строки, которые можно использовать для управления тем, когда генерируются (или нет) предупреждения:
- -w
-
Это существующий флаг. Если лексическая прагма предупреждений не используется ни в одном из ваших кодов или используемых модулей, этот флаг включит предупреждения повсюду. См. «Обратная совместимость» для получения подробностей о взаимодействии этого флага с лексическими предупреждениями.
- -W
-
Если флаг -W используется в командной строке, он включит все предупреждения в программе независимо от того, были ли предупреждения отключены локально с помощью
no warningsили$^W =0. Это включает все файлы, которые подключаются с помощьюuse,requireилиdo. Представьте это как Perl-эквивалент команды «lint». - -X
-
Делает прямо противоположное флагу -W, т.е. отключает все предупреждения.
Обратная совместимость
Если вы привыкли работать с версией Perl до появления лексически-ограниченных предупреждений или у вас есть код, который использует как лексические предупреждения, так и $^W, этот раздел опишет их взаимодействие.
Как лексические предупреждения взаимодействуют с -w/$^W:
-
Если ни один из трёх флагов командной строки (-w, -W или -X), которые контролируют предупреждения, не используется, и ни
$^W, ни прагмаwarningsне используются, тогда предупреждения по умолчанию будут включены, а необязательные предупреждения — отключены. Это означает, что устаревший код, который не пытается контролировать предупреждения, будет работать без изменений. -
Флаг -w просто устанавливает глобальную переменную
$^W, как и в 5.005. Это означает, что любой устаревший код, который в настоящее время полагается на манипулирование$^Wдля управления поведением предупреждений, по-прежнему будет работать так же. -
Помимо того, что теперь это булев, переменная
$^Wработает точно так же, ужасно, без контроля, глобально, за исключением того, что не может отключать/включать предупреждения по умолчанию. -
Если фрагмент кода находится под контролем прагмы
warnings, как переменная$^W, так и флаг -w будут игнорироваться в области действия лексического предупреждения. -
Единственный способ переопределить настройку лексических предупреждений — использовать флаги командной строки -W или -X.
Совместное действие пунктов 3 и 4 позволяет коду, использующему прагму warnings, управлять поведением предупреждений типа $^W (с помощью local $^W=0), если он действительно хочет, но не наоборот.
Иерархия категорий
Была определена иерархия «категорий», чтобы позволить группам предупреждений включаться/выключаться изолированно.
Текущая иерархия:
all -+
|
+- closure
|
+- deprecated
|
+- exiting
|
+- experimental --+
| |
| +- experimental::alpha_assertions
| |
| +- experimental::bitwise
| |
| +- experimental::const_attr
| |
| +- experimental::declared_refs
| |
| +- experimental::isa
| |
| +- experimental::lexical_subs
| |
| +- experimental::postderef
| |
| +- experimental::private_use
| |
| +- experimental::re_strict
| |
| +- experimental::refaliasing
| |
| +- experimental::regex_sets
| |
| +- experimental::script_run
| |
| +- experimental::signatures
| |
| +- experimental::smartmatch
| |
| +- experimental::try
| |
| +- experimental::uniprop_wildcards
| |
| +- experimental::vlb
| |
| +- experimental::win32_perlio
|
+- glob
|
+- imprecision
|
+- io ------------+
| |
| +- closed
| |
| +- exec
| |
| +- layer
| |
| +- newline
| |
| +- pipe
| |
| +- syscalls
| |
| +- unopened
|
+- locale
|
+- misc
|
+- missing
|
+- numeric
|
+- once
|
+- overflow
|
+- pack
|
+- portable
|
+- recursion
|
+- redefine
|
+- redundant
|
+- regexp
|
+- severe --------+
| |
| +- debugging
| |
| +- inplace
| |
| +- internal
| |
| +- malloc
|
+- shadow
|
+- signal
|
+- substr
|
+- syntax --------+
| |
| +- ambiguous
| |
| +- bareword
| |
| +- digit
| |
| +- illegalproto
| |
| +- parenthesis
| |
| +- precedence
| |
| +- printf
| |
| +- prototype
| |
| +- qw
| |
| +- reserved
| |
| +- semicolon
|
+- taint
|
+- threads
|
+- uninitialized
|
+- unpack
|
+- untie
|
+- utf8 ----------+
| |
| +- non_unicode
| |
| +- nonchar
| |
| +- surrogate
|
+- void Как и прагма «strict», все эти категории могут быть объединены
use warnings qw(void redefine);
no warnings qw(io syntax untie); Также, как и прагма «strict», если в данной области существует более одной инстанции прагмы warnings, кумулятивный эффект является аддитивным.
use warnings qw(void); # only "void" warnings enabled
...
use warnings qw(io); # only "void" & "io" warnings enabled
...
no warnings qw(void); # only "io" warnings enabled Чтобы определить, к какой категории относится конкретное предупреждение, см. perldiag.
Примечание: До Perl 5.8.0, лексическая категория предупреждений «deprecated» была подкатегорией категории «syntax». Теперь она является категорией верхнего уровня.
Примечание: До 5.21.0, лексическая категория предупреждений «missing» была внутренне определена как идентичная категории «uninitialized». Теперь она является категорией верхнего уровня.
Критические предупреждения
Наличие слова «FATAL» в списке категорий повысит предупреждения в этих категориях до критических ошибок в этой лексической области.
ПРИМЕЧАНИЕ: Критические предупреждения следует использовать с осторожностью, особенно FATAL => 'all'.
Библиотеки, использующие warnings::warn для пользовательских категорий предупреждений, обычно не ожидают, что warnings::warn будет критическим, и в результате могут оказаться в неожиданном состоянии. Для XS-модулей, выдавающих предупреждения с категориями, такие непредвиденные исключения также могут выявлять утечки памяти.
Более того, сам интерпретатор Perl имел серьёзные ошибки, связанные с критическими предупреждениями. Для обзора решённых и нерешённых проблем, по состоянию на январь 2015 года, см. эту запись в perl5-porters.
Хотя некоторые разработчики считают, что критизация некоторых предупреждений является полезной техникой защитного программирования, использование FATAL => 'all' для критизации всех возможных категорий предупреждений — включая пользовательские — особенно рискованно. Поэтому использование FATAL => 'all' не рекомендуется.
Модуль strictures на CPAN предлагает один пример подмножества предупреждений, которое, по мнению авторов модуля, относительно безопасно критизировать.
END_OF_DOCUMENT_MARKERПРИМЕЧАНИЕ: Пользователи предупреждений FATAL, особенно те, кто использует FATAL => 'all', должны полностью осознавать, что они рискуют будущей переносимостью своих программ. Perl не делает никаких обязательств по тому, чтобы не вводить новые предупреждения или категории предупреждений в будущем; фактически, мы прямо оставляем за собой право сделать это. Код, который сейчас может не генерировать предупреждения, может выдать предупреждение в будущей версии Perl, если команда разработчиков Perl5 сочтёт это в интересах сообщества. Если код, использующий предупреждения FATAL, сломается из-за введения нового предупреждения, мы НЕ будем рассматривать это как несовместимое изменение. Пользователи предупреждений FATAL должны проявлять особую осторожность во время обновлений, чтобы проверить, не вызывает ли их код никаких новых предупреждений, и должны обращать особое внимание на мелкий шрифт документации используемых функций, чтобы убедиться, что они не используют функции, которые документированы как рискованные, устаревшие или не определённые, или где в документации сказано «так что не делайте этого», или что-то с таким же смыслом и духом. Использование таких функций в сочетании с предупреждениями FATAL ВСЁ НА РИСКЕ ПОЛЬЗОВАТЕЛЯ.
В данной документации описывается, как использовать предупреждения FATAL, но портеры Perl5 настоятельно рекомендуют вам понять риски, прежде чем делать это, особенно для кода библиотек, предназначенного для использования другими, так как нет способа, чтобы пользователи последующих этапов могли изменить выбор категорий fatal.
В коде ниже, использование time, length и join может вызвать предупреждение "Useless use of xxx in void context".
use warnings;
time;
{
use warnings FATAL => qw(void);
length "abc";
}
join "", 1,2,3;
print "done\n"; При выполнении он выводит такой вывод
Useless use of time in void context at fatal line 3.
Useless use of length in void context at fatal line 7. Область, где используется length, повысила категорию предупреждений void до уровня ошибки fatal, поэтому программа завершается немедленно при обнаружении предупреждения.
Чтобы явно отключить предупреждение «FATAL», просто отключите предупреждение, с которым оно связано. Например, чтобы отключить предупреждение «void» в приведённом выше примере, подойдет любое из этих решений:
no warnings qw(void);
no warnings FATAL => qw(void); Если вы хотите понизить предупреждение, которое было повышено до уровня fatal, обратно к обычному предупреждению, вы можете использовать ключевое слово «NONFATAL». Например, код ниже повысит все предупреждения до уровня fatal, за исключением тех, которые относятся к категории «syntax».
use warnings FATAL => 'all', NONFATAL => 'syntax'; Начиная с Perl 5.20, вместо use warnings FATAL => 'all'; можно использовать:
use v5.20; # Perl 5.20 or greater is required for the following
use warnings 'FATAL'; # short form of "use warnings FATAL => 'all';" Однако, вы всё ещё должны следовать рекомендациям, приведённым ранее в этом разделе, относительно использования use warnings FATAL = 'all';>.
Если вы хотите, чтобы ваша программа была совместима с версиями Perl до 5.20, вы должны использовать use warnings FATAL => 'all'; вместо. (В предыдущих версиях Perl поведение операторов use warnings 'FATAL';, use warnings 'NONFATAL'; и no warnings 'FATAL'; было неопределённым; они не вели себя так, как будто включали часть => 'all'. Начиная с версии 5.20, они ведут себя именно так.)
Сообщения о предупреждениях из модуля
Предикат warnings предоставляет ряд функций, полезных авторам модулей. Они используются, когда вы хотите сообщить предупреждение, специфичное для модуля, вызывающему модулю, который включил предупреждения с помощью предикатов warnings.
Рассмотрим модуль MyMod::Abc ниже.
package MyMod::Abc;
use warnings::register;
sub open {
my $path = shift;
if ($path !~ m#^/#) {
warnings::warn("changing relative path to /var/abc")
if warnings::enabled();
$path = "/var/abc/$path";
}
}
1; Вызов функции warnings::register создаст новую категорию предупреждений под названием «MyMod::Abc», то есть имя новой категории соответствует текущему имени пакета. Функция open в модуле отобразит сообщение о предупреждении, если ей будет передан относительный путь в качестве параметра. Это предупреждение будет отображено только в том случае, если код, использующий MyMod::Abc, фактически включил их с помощью предикатов warnings, как показано ниже.
use MyMod::Abc;
use warnings 'MyMod::Abc';
...
abc::open("../fred.txt"); Также возможно проверить, установлены ли предопределённые категории предупреждений в вызывающем модуле с помощью функции warnings::enabled. Рассмотрим этот фрагмент кода:
package MyMod::Abc;
sub open {
if (warnings::enabled("deprecated")) {
warnings::warn("deprecated",
"open is deprecated, use new instead");
}
new(@_);
}
sub new
...
1; Функция open устарела, поэтому включён код для отображения сообщения о предупреждении всякий раз, когда вызывающий модуль (по крайней мере) имеет включённую категорию предупреждений «deprecated». Что-то вроде этого.
use warnings 'deprecated';
use MyMod::Abc;
...
MyMod::Abc::open($filename); Для фактического отображения сообщений о предупреждениях следует использовать функцию warnings::warn или warnings::warnif. Это связано с тем, что они могут использовать возможность повышения предупреждений до ошибок fatal. Таким образом, в этом случае
use MyMod::Abc;
use warnings FATAL => 'MyMod::Abc';
...
MyMod::Abc::open('../fred.txt'); функция warnings::warnif обнаружит это и завершится после отображения сообщения о предупреждении.
Три функции предупреждений, warnings::warn, warnings::warnif и warnings::enabled, могут необязательно принимать ссылку на объект вместо имени категории. В этом случае функции будут использовать имя класса объекта в качестве категории предупреждений.
Рассмотрим этот пример:
package Original;
no warnings;
use warnings::register;
sub new
{
my $class = shift;
bless [], $class;
}
sub check
{
my $self = shift;
my $value = shift;
if ($value % 2 && warnings::enabled($self))
{ warnings::warn($self, "Odd numbers are unsafe") }
}
sub doit
{
my $self = shift;
my $value = shift;
$self->check($value);
# ...
}
1;
package Derived;
use warnings::register;
use Original;
our @ISA = qw( Original );
sub new
{
my $class = shift;
bless [], $class;
}
1; Код ниже использует оба модуля, но включает предупреждения только из Derived.
use Original;
use Derived;
use warnings 'Derived';
my $x = Original->new();
$x->doit(1);
my $y = Derived->new();
$x->doit(1); При выполнении этого кода только объект Derived, $y, сгенерирует предупреждение.
Odd numbers are unsafe at main.pl line 7 Обратите также внимание, что предупреждение сообщается на строке, где объект используется впервые.
При регистрации новых категорий предупреждений вы можете добавить больше имён в warnings::register так:
package MyModule;
use warnings::register qw(format precision);
...
warnings::warnif('MyModule::format', '...'); ФУНКЦИИ
Примечание: Функции с именами, оканчивающимися на _at_level, были добавлены в Perl 5.28.
- use warnings::register
-
Создаёт новую категорию предупреждений с тем же именем, что и пакет, где используется предикат.
- warnings::enabled()
-
Использует категорию предупреждений с тем же именем, что и текущий пакет.
Возвращает TRUE, если эта категория предупреждений включена в вызывающем модуле. В противном случае возвращает FALSE.
- warnings::enabled($category)
-
Возвращает TRUE, если категория предупреждений,
$category, включена в вызывающем модуле. В противном случае возвращает FALSE. - warnings::enabled($object)
-
Использует имя класса для ссылки на объект,
$object, в качестве категории предупреждений.Возвращает TRUE, если эта категория предупреждений включена в первом области видимости, где используется объект. В противном случае возвращает FALSE.
- warnings::enabled_at_level($category, $level)
-
Аналогично
warnings::enabled, но $level указывает точный фрейм вызова, 0 — непосредственный вызывающий. - warnings::fatal_enabled()
-
Возвращает TRUE, если категория предупреждений с тем же именем, что и текущий пакет, была установлена в FATAL в вызывающем модуле. В противном случае возвращает FALSE.
- warnings::fatal_enabled($category)
-
Возвращает TRUE, если категория предупреждений
$categoryбыла установлена в FATAL в вызывающем модуле. В противном случае возвращает FALSE. - warnings::fatal_enabled($object)
-
Использует имя класса для ссылки на объект,
$object, в качестве категории предупреждений.Возвращает TRUE, если эта категория предупреждений была установлена в FATAL в первой области видимости, где используется объект. В противном случае возвращает FALSE.
- warnings::fatal_enabled_at_level($category, $level)
-
Аналогично
warnings::fatal_enabled, но $level указывает точный фрейм вызова, 0 — непосредственный вызывающий. - warnings::warn($message)
-
Выводит
$messageв STDERR.Использует категорию предупреждений с тем же именем, что и текущий пакет.
Если эта категория предупреждений была установлена в «FATAL» в вызывающем модуле, завершается с ошибкой. В противном случае возвращает результат.
- warnings::warn($category, $message)
-
Выводит
$messageв STDERR.Если категория предупреждений,
$category, установлена в «FATAL» в вызывающем модуле, завершается с ошибкой. В противном случае возвращает результат. - warnings::warn($object, $message)
-
Выводит
$messageв STDERR.Использует имя класса для ссылки на объект,
$object, в качестве категории предупреждений.Если эта категория предупреждений была установлена в «FATAL» в области видимости, где
$objectиспользуется впервые, завершается с ошибкой. В противном случае возвращает результат. - warnings::warn_at_level($category, $level, $message)
-
Аналогично
warnings::warn, но $level указывает точный фрейм вызова, 0 — непосредственный вызывающий. - warnings::warnif($message)
-
Эквивалентно:
if (warnings::enabled()) { warnings::warn($message) } - warnings::warnif($category, $message)
-
Эквивалентно:
if (warnings::enabled($category)) { warnings::warn($category, $message) } - warnings::warnif($object, $message)
-
Эквивалентно:
if (warnings::enabled($object)) { warnings::warn($object, $message) } - warnings::warnif_at_level($category, $level, $message)
-
Аналогично
warnings::warnif, но $level указывает точный фрейм вызова, 0 — непосредственный вызывающий. - warnings::register_categories(@names)
-
Регистрирует категории предупреждений для заданных имён и предназначена в основном для использования с предикатом warnings::register.
См. также "Предикаты в perlmodlib" и perldiag.
© 1993–2021 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.34.0/warnings