Spec-Zone.ru › Perl 5.38

предупреждения

СОДЕРЖАНИЕ

  • ИМЯ
  • СИНОПСИС
  • ОПИСАНИЕ
    • Стандартные и необязательные предупреждения
    • «Отрицательные предупреждения»
    • Что не так с -w и $^W
    • Управление предупреждениями из командной строки
    • Обратная совместимость
    • Иерархия категорий
    • Предупреждения с фатальным исходом
    • Отчёт о предупреждениях из модуля
  • ФУНКЦИИ

ИМЯ

warnings - Perl-прагма для управления необязательными предупреждениями

СИНОПСИС

use warnings;
no warnings;

# Standard warnings are enabled by use v5.35 or above
use v5.35;

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");

ОПИСАНИЕ

Прагма 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 — нет.

Все предупреждения автоматически включаются в области действия объявления use v5.35 (или выше).

Стандартные и необязательные предупреждения

До появления лексических предупреждений в 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';

По мере того, как экспериментальные функции становятся обычными функциями Perl, соответствующие предупреждения больше не выводятся. Они также перестают отображаться в иерархии категорий ниже.

Всё ещё возможно запрашивать включение или отключение этих предупреждений, но это не повлияет на результат.

Что не так с -w и $^W

Хотя очень полезно, большая проблема с использованием -w в командной строке для включения предупреждений заключается в том, что это «всё или ничего». Возьмём типичный случай, когда вы пишете Perl-программу. Части кода вы напишете сами, но, очень вероятно, что вы будете использовать написанные ранее Perl-модули. Если вы используете флаг -w в этом случае, вы включите предупреждения в фрагментах кода, которые вы не писали.

Аналогично, использование $^W для отключения или включения блоков кода фундаментально неверно. Начнём с того, что, скажем, вы хотите отключить предупреждения в блоке кода. Вы можете ожидать, что этого достаточно:

{
    local ($^W) = 0;
    my $x =+ 2;
    my $y; chop $y;
}

При выполнении этого кода с флагом -w будет выведено предупреждение для строки %%%CODE_BLOCK_41%%: "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:

  1. Если ни один из трёх флагов командной строки (-w, -W или -X), контролирующих предупреждения, не используется, и ни $^W ни прагма warnings не используются, то стандартные предупреждения будут включены, а необязательные — отключены. Это означает, что устаревший код, не пытающийся контролировать предупреждения, будет работать без изменений.

  2. Флаг -w просто устанавливает глобальную переменную $^W как в 5.005. Это означает, что любой устаревший код, который в настоящее время полагается на манипулирование $^W для управления поведением предупреждений, всё ещё будет работать так же.

  3. Помимо того, что теперь это булево значение, переменная $^W работает точно так же, как и раньше — в ужасно неконтролируемом глобальном режиме, за исключением того, что она не может отключать/включать стандартные предупреждения.

  4. Если фрагмент кода находится под управлением прагмы warnings , переменная $^W и флаг -w будут игнорироваться в пределах области действия лексического предупреждения.

  5. Единственный способ переопределить настройку лексических предупреждений — это флаги командной строки -W или -X.

Совместное действие 3 и 4 заключается в том, что это позволит коду, использующему прагму warnings, контролировать поведение предупреждений типа $^W (используя local $^W=0), если это действительно нужно, но не наоборот.

Иерархия категорий

Была определена иерархия «категорий» для возможности включения/отключения групп предупреждений в отдельности.

Текущая иерархия:

all -+
     |
     +- closure
     |
     +- deprecated ----+
     |                 |
     |                 +- deprecated::apostrophe_as_package_separator
     |                 |
     |                 +- deprecated::delimiter_will_be_paired
     |                 |
     |                 +- deprecated::dot_in_inc
     |                 |
     |                 +- deprecated::goto_construct
     |                 |
     |                 +- deprecated::smartmatch
     |                 |
     |                 +- deprecated::unicode_property_name
     |                 |
     |                 +- deprecated::version_downgrade
     |
     +- exiting
     |
     +- experimental --+
     |                 |
     |                 +- experimental::args_array_with_signatures
     |                 |
     |                 +- experimental::builtin
     |                 |
     |                 +- experimental::class
     |                 |
     |                 +- experimental::const_attr
     |                 |
     |                 +- experimental::declared_refs
     |                 |
     |                 +- experimental::defer
     |                 |
     |                 +- experimental::extra_paired_delimiters
     |                 |
     |                 +- experimental::for_list
     |                 |
     |                 +- experimental::private_use
     |                 |
     |                 +- experimental::re_strict
     |                 |
     |                 +- experimental::refaliasing
     |                 |
     |                 +- experimental::regex_sets
     |                 |
     |                 +- experimental::try
     |                 |
     |                 +- experimental::uniprop_wildcards
     |                 |
     |                 +- experimental::vlb
     |
     +- glob
     |
     +- imprecision
     |
     +- io ------------+
     |                 |
     |                 +- closed
     |                 |
     |                 +- exec
     |                 |
     |                 +- layer
     |                 |
     |                 +- newline
     |                 |
     |                 +- pipe
     |                 |
     |                 +- syscalls
     |                 |
     |                 +- unopened
     |
     +- locale
     |
     +- misc
     |
     +- missing
     |
     +- numeric
     |
     +- once
     |
     +- overflow
     |
     +- pack
     |
     +- portable
     |
     +- recursion
     |
     +- redefine
     |
     +- redundant
     |
     +- regexp
     |
     +- scalar
     |
     +- 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' не рекомендуется.

END_OF_DOCUMENT_MARKER

Модуль strictures на CPAN предоставляет пример набора предупреждений, которые, по мнению авторов модуля, относительно безопасно использовать с параметром fatal.

ПРИМЕЧАНИЕ: Пользователи предупреждений FATAL, особенно те, кто использует FATAL => 'all', должны полностью понимать, что они рискуют будущей переносимостью своих программ, делая это. Perl не даёт никаких гарантий, что в будущем не будут добавлены новые предупреждения или категории предупреждений; мы, по сути, оставляем за собой право сделать это. Код, который сейчас не вызывает предупреждений, может вызывать их в будущих версиях Perl, если команда разработчиков Perl5 сочтёт это необходимым для сообщества. Если код с предупреждениями FATAL сломается из-за введения нового предупреждения, мы НЕ будем рассматривать это как несовместимое изменение. Пользователи предупреждений FATAL должны быть особенно внимательны во время обновлений, чтобы проверить, не вызывает ли их код новых предупреждений, и должны обращать особое внимание на мелкие детали документации используемых функций, чтобы убедиться, что они не используют функции, которые документированы как рискованные, устаревшие или не определённые, или где в документации сказано «не делайте этого», или что-то с подобным смыслом и духом. Использование таких функций в сочетании с предупреждениями FATAL целиком на риске пользователя.

В следующем руководстве описано, как использовать предупреждения FATAL, но портеры Perl5 настоятельно рекомендуют вам понять риски, прежде чем делать это, особенно для кода библиотеки, предназначенного для использования другими, так как нет способа для пользователей по нижней части изменить выбор категорий для вывода предупреждений.

В приведенном ниже коде использование time, length и join может привести к предупреждению "Useless use of xxx in void context".

%%%CODE_BLOCK_83%%

При запуске он выводит этот вывод

%%%CODE_BLOCK_85%%

Область, где используется length, повысила категорию предупреждений void до критической ошибки, поэтому программа немедленно завершается при обнаружении предупреждения.

Чтобы явно отключить предупреждение «FATAL», просто отключите предупреждение, с которым оно связано. Например, чтобы отключить предупреждение «void» в приведённом выше примере, можно сделать так:

no warnings qw(void);
no warnings FATAL => qw(void);

Если вы хотите понизить предупреждение, которое было повышено до критической ошибки, обратно до обычного предупреждения, можно использовать ключевое слово «NONFATAL». Например, приведенный ниже код повысит все предупреждения до критических ошибок, за исключением тех, которые относятся к категории «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, они это делают.)

Сообщения о предупреждениях из модуля

Pragma warnings предоставляет ряд функций, полезных авторам модулей. Они используются, когда вы хотите сообщить модуле о предупреждении, специфичном для модуля, вызывающему модулю, который включил предупреждения с помощью pragmy 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, фактически включил их с помощью pragmy 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, поскольку они могут использовать функцию, которая позволяет повышать предупреждения до критических ошибок. Таким образом,

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

Создаёт новую категорию предупреждений с тем же именем, что и пакет, в котором используется pragma.

warnings::enabled()

Использует категорию предупреждений с тем же именем, что и текущий пакет.

Возвращает ИСТИНУ, если эта категория предупреждений включена в вызывающем модуле. В противном случае возвращает ЛОЖЬ.

warnings::enabled($category)

Возвращает ИСТИНУ, если категория предупреждений, $category, включена в вызывающем модуле. В противном случае возвращает ЛОЖЬ.

warnings::enabled($object)

Использует имя класса для ссылки на объект, $object, в качестве категории предупреждений.

Возвращает ИСТИНУ, если эта категория предупреждений включена в первом объёме, где используется объект. В противном случае возвращает ЛОЖЬ.

warnings::enabled_at_level($category, $level)

Как warnings::enabled, но $level определяет точный кадр вызова, 0 — непосредственный вызывающий.

warnings::fatal_enabled()

Возвращает ИСТИНУ, если категория предупреждений с тем же именем, что и текущий пакет, установлена в FATAL в вызывающем модуле. В противном случае возвращает ЛОЖЬ.

warnings::fatal_enabled($category)

Возвращает ИСТИНУ, если категория предупреждений $category установлена в FATAL в вызывающем модуле. В противном случае возвращает ЛОЖЬ.

warnings::fatal_enabled($object)

Использует имя класса для ссылки на объект, $object, в качестве категории предупреждений.

Возвращает ИСТИНУ, если эта категория предупреждений установлена в FATAL в первом объёме, где используется объект. В противном случае возвращает ЛОЖЬ.

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)

Эта функция регистрирует категории предупреждений для заданных имён и предназначена в основном для использования с pragma warnings::register.

См. также "Pragmatic Modules" в perlmodlib и perldiag.

© 1993–2023 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.38.0/warnings

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API