2008-09-18 2 views
3

Я столкнулся с тем, что кажется проблемой с переменной областью, с которой я не сталкивался раньше. Я использую модуль CGI Perl и вызов метода do() DBI. Вот структура кода, немного упрощен:Perl: проблема с переменной областью с модулями CGI и DBI

use DBI; 
use CGI qw(:cgi-lib); 
&ReadParse; 
my $dbh = DBI->connect(...............); 
my $test = $in{test}; 
$dbh->do(qq{INSERT INTO events VALUES (?,?,?)},undef,$in{test},"$in{test}",$test); 

Переменная заполнитель # 1 оценивает, как будто это неинициализированным. Остальные две переменные-заполнители работают.

Вопрос: Почему% в хеше недоступен в контексте do(), если я не оберну его в двойные кавычки (# 2 placeholder) или переназначить значение новой переменной (# 3 placeholder)?

Я думаю, что это связано с тем, как функция ReadParse() модуля CGI присваивает области значение% в хеше, но я не знаю, насколько Perl просматривает достаточно хорошо, чтобы понять, почему% in доступен на верхнем уровне, но не из моей инструкции do().

Если кто-то действительно понимает проблему обзора, есть ли лучший способ справиться с этим? Обертывание всех% ссылок в двойных кавычках кажется немного беспорядочным. Создание новых переменных для каждого параметра запроса нереально.

Для того, чтобы быть ясным, мой вопрос касается проблемы с переменными областями. Я понимаю, что ReadParse() не является рекомендуемым методом для захвата параметров запроса с помощью CGI.

Я использую Perl 5.8.8, CGI 3.20 и DBI 1.52. Заранее благодарю всех, кто это читает.

@Pi & @Bob, спасибо за предложения. Предварительное объявление области для% in не имеет эффекта (и я всегда использую строгую). Результат будет таким же, как и раньше: в db col1 имеет значение null, а cols 2 & 3 установлены в ожидаемое значение.

Для справки, вот функция ReadParse (см. Ниже). Это стандартная функция, которая является частью CGI.pm. Как я понимаю, я не имел в виду, чтобы инициализировать% в хэш (кроме удовлетворяющих строгим) для целей настройки масштаба, так как функция представляется мне справиться с этим:

sub ReadParse { 
    local(*in); 
    if (@_) { 
     *in = $_[0]; 
    } else { 
    my $pkg = caller(); 
     *in=*{"${pkg}::in"}; 
    } 
    tie(%in,CGI); 
    return scalar(keys %in); 
} 

Я думаю, мой вопрос это лучший способ получить% in hash в контексте do()? Еще раз спасибо! Надеюсь, это правильный способ предоставить дополнительную информацию по моему первоначальному вопросу.

@ Dan: Я слышал, что в отношении синтаксиса ReadParse &. Обычно я использовал CGI :: ReadParse(), но в этом случае я думал, что лучше всего точно придерживаться того, как the CGI.pm documentation has it.

+0

объявите его как мой в том же контексте вашего звонка. Вы не назначаете это ни на что. Почему вы используете *, когда вам нужен только хэш? Это очень сложная подпрограмма. Возможно, я смогу работать с вами, чтобы очистить или лучше понять ваши потребности. Можете ли вы показать нам, где вы называете этот суб? – 2008-09-18 02:12:54

ответ

1

В документации по DBI: привязка привязанной переменной в настоящее время не работает.

DBI довольно сложный под капотом и, к сожалению, проходит через некоторые колебания, чтобы быть эффективными, которые вызывают проблемы. Я согласен со всеми, кто говорит, чтобы избавиться от уродливого старого кода стиля cgi-lib. Достаточно неприятно делать CGI без хорошей структуры (go Catalyst), не говоря уже о том, что уже давно устарело.

3

use strict;. Всегда.

Try объявляя

our %in; 

и увидеть, если это помогает. В противном случае strict может вызвать более полезную ошибку.

+0

Это было бы хорошим советом для начинающего программиста, но я вне этого. По моей вине, я не уточнил в своем вопросе, что «упрощенная бит» означала, что я оставляю основные декларации, необходимые для строгой прагмы. – Wick 2008-09-19 10:39:52

2

Во-первых, это не в контексте/сфере действия. Он все еще находится в контексте основного или глобального. Вы не оставляете контекст, пока не введете {} каким-либо образом, связанным с подпрограммами или разными «классами» в perl. В пределах() parens вы не оставляете область действия.

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

Не могли бы вы дать нам более представительный пример вашего кода? Где вы устанавливаете% IN и как?

2

Что-то там очень сломано. Перспектива Perl относительно проста, и вы вряд ли наткнетесь на что-нибудь странное, если не будете делать что-то глупое. Как было предложено, включите строгую прагму (и предупреждения тоже. На самом деле вы должны использовать оба варианта).

Сложно сказать, что происходит, не имея возможности увидеть, как определяется% in (это как-то связано с этим неприятным вызовом ReadParse? Почему вы вызываете его с ведущим &, или этим синтаксисом? считается мертвым и давно ушел). Я предлагаю разместить немного больше кода, так что мы можем видеть, что происходит ..

+0

Я надеюсь, что я наткнулся на что-то странное :) Я попытался устранить все, что осталось до публикации. Для справки: строгие и предупреждения включены. % in определяется и управляется в ReadParse(), часть CGI.pm (стандартный модуль Perl, а не мой код). – Wick 2008-09-18 03:33:42

4

Это на самом деле не выглядеть как вы используете его, как описано в документации: https://metacpan.org/pod/CGI#COMPATIBILITY-WITH-CGI-LIB.PL

Если вы должны использовать его , затем CGI :: ReadParse(); кажется более разумным и менее жестоким синтаксисом. Хотя я не вижу, чтобы это имело большое значение в этой ситуации, но тогда это привязанная переменная, так кто, черт возьми, знает, что она делает;)

Есть ли определенная причина, по которой вы не можете использовать более общие $ cgi-> param ('foo') синтаксис? Это немного чище, и filths ваше пространство имен в значительно более предсказуемо ..

+0

Я работаю над обновлением устаревшего кода .. ReadParse /% в дерьме определенно получает консервы :) Мне просто интересно, потому что есть кое-что фундаментальное в области изменения переменных, о котором я не знаю.BTW попробовал CGI :: ReadParse(); .. нет разницы, но спасибо, что указал. – Wick 2008-09-18 02:32:39

+0

Что касается использования синтаксиса $ query-> param(), я ссылался на это в своем первоначальном сообщении. Хотя это оборачивает проблему, она не объясняет, что происходит, что является главной темой моего вопроса. Плохой код или нет, я хочу понять, что происходит, поэтому в какой-то другой ситуации это не повторится. – Wick 2008-09-18 03:20:17

+0

Очень жаль, что этот ответ набирается, потому что 1) разница в синтаксисе вызова функции не является проблемой, и 2) мой вопрос конкретно НЕ о лучшем способе захвата параметров запроса. Не обижайтесь на Дэна, просто надеясь получить больше ответов на тему. – Wick 2008-09-19 10:34:11

-1

Попробуйте

% в = ReadParse();

, но я сомневаюсь в этом. Вы пытаетесь получить параметры запроса или что-то еще?

+0

ОШИБКА: Нечетное количество элементов в хэш-присваивании в (и т.д.). ... ReadParse() возвращает скаляр (ключи% in), поэтому я не думаю, что назначение результата функции хешу будет работать. – Wick 2008-09-18 02:45:20

+0

Я обновляю устаревший код и, безусловно, не сохраняю ReadParse() и% в дерьме! В основном меня просто беспокоит, что я не понимаю ничего принципиального в области изменения переменных. Знаешь что я имею ввиду? Это принцип проблемы. Обычный метод $ query-> param ('x') работает нормально. Еще раз спасибо – Wick 2008-09-18 02:46:50

+1

ReadParse предназначен для устаревших систем, используя старый API cgi-lib.pl. Используйте современные вещи! :) – 2008-09-21 22:25:47

0

Хорошо, попробуйте следующее:

 
use CGI; 
my %in; 
CGI::ReadParse(\%in); 

Это может помочь, как это на самом деле, используя переменное, вы объявили, и, следовательно, может контролировать объем (плюс это будет препятствовать вам use strict без другой гадости, что может быть мутят воду)

+0

Нет! ReadParse устанавливается в таблицу символов. Если вы передадите ему какое-либо лекарство вообще, он ожидает типglob, а не ссылку на лексику. – 2008-09-18 02:56:07

+0

Нет кубиков. Невероятно, что переменный параметр не будет работать. WTF! Что сходит с ума, так это то, что замена двух последних строк: my% in = ('test', 'hello world'); .. отлично работает. Это должно быть что-то с функцией ReadParse, связывающей область переменных? Это то, с чем я не знаком. Спасибо – Wick 2008-09-18 03:05:56

3

Я не знаю, что это неправильно, но я могу вам сказать, некоторые вещи, которые не:

  • Это не проблема обзорной. Если бы это было тогда, то ни один из примеров $in{test} не сработает.
  • Это не архаичный & синтаксис вызова. (Это не «правильно», но в этом случае это безвредно.)

ReadParse - это неприятный фрагмент кода. Он отображает таблицу символов, чтобы создать глобальную переменную% in в вызывающем пакете. Хуже всего то, что это привязанная переменная, поэтому доступ к ней может (теоретически) сделать что угодно. Рассматривая исходный код для CGI.pm, метод FETCH просто вызывает метод params() для получения данных. Я понятия не имею, почему выборка в $dbh->do() не работает.

2

Какую версию DBI вы используете? От взгляда на DBI changelog кажется, что версии до 1.00 не поддерживают аргумент атрибута. Я подозреваю, что «неинициализированный» $in{test} на самом деле является undef, который вы переходите на $dbh->do().

0

Поскольку это начинает выглядеть как проблема tie(), попробуйте выполнить следующий эксперимент. Сохранить как foo.pl и запустить его как perl foo.pl "x=1"

use CGI; 

CGI::ReadParse(); 
p($in{x}, "$in{x}"); 

sub p { my @a = @_; print "@a\n" } 

Он должен печатать 1 1. Если это не так, мы нашли преступника.

2

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

Похоже, что DBI (или DBD, не уверенный, где используются параметры привязки) не соблюдает галстучную магию. Обходным путем было бы выровнять или скопировать то, что вы передаете ему, как и ваш второй и третий параметры.

Простой тест с использованием SQLite и DBI 1,53 показывает, что он работает нормально:

$ perl -MDBI -we'sub TIEHASH { bless {} } sub FETCH { "42" } tie %x, "main" or die; my $dbh = DBI->connect("dbi:SQLite:dbname=dbfile","",""); $dbh->do("create table foo (bar char(80))"); $dbh->do("insert into foo values (?)", undef, $x{foo}); print "got: " . $dbh->selectrow_array("select bar from foo") . "\n"; $dbh->do("drop table foo")' 
got: 42 

Care поделиться тем, что базы данных вы используете?

0

Я все еще хотел бы отследить причину этого. Опять же, какую базу данных вы используете (какой модуль DBD и какая версия?)

0

Я только что попробовал вашу тестовую кошечку от http://www.carcomplaints.com/test/test.pl.txt, и это сразу работает на моем компьютере, никаких проблем. Я получаю три значения, как ожидалось. Я не запускать его как CGI, но с использованием:

... 
use CGI qw/-debug/; 
... 

Я пишу переменную на консоли (test=test) и сценарии вставки без проблем.

Если вы оставите это, tt введет пустую строку и два NULL. Это связано с тем, что вы интерполируете значение в строку. Это приведет к строке со значением $in{test}, которая равна undef. undef строит пустую строку, которая является тем, что вставляется в базу данных.

Смежные вопросы