传递哈希值到子程序时,Perl中引用和反引用哈希值是什么?

5

我已经为这个问题纠结了约5个小时,我真的很沮丧,需要一些帮助。

我正在编写一个Perl脚本,从MySQL表中提取作业,然后执行各种数据库管理任务。当前任务是“创建数据库”。脚本成功创建了数据库,但当我要为PHP开发人员生成配置文件时,它就崩溃了。

我认为这是一个引用和解引用变量的问题,但我不确定具体发生了什么。我认为在这个函数调用之后,$$result{'databaseName'}发生了一些变化。这是我得到结果的方法:$result = $select->fetchrow_hashref()

下面是我的函数调用和函数实现:

函数调用(第127行):

generateConfig($$result{'databaseName'}, $newPassword, "php");

函数实现:

sub generateConfig {
    my($inName) = $_[0];
    my($inPass) = $_[1];
    my($inExt)  = $_[2];

    my($goodData) = 1;
    my($select)   = $dbh->prepare("SELECT id FROM $databasesTableName WHERE name = '$inName'");
    my($path)     = $documentRoot.$inName."_config.".$inExt;
    $select->execute();

    if ($select->rows < 1 ) {
            $goodData = 0;
    }

    while ( $result = $select->fetchrow_hashref() )
    {
            my($insert) = $dbh->do("INSERT INTO $configTableName(databaseId, username, password, path)".
                                   "VALUES('$$result{'id'}', '$inName', '$inPass', '$path')");

    }

    return 1;
    }

错误:

Use of uninitialized value in concatenation (.) or string at ./dbcreator.pl line 142.
Use of uninitialized value in concatenation (.) or string at ./dbcreator.pl line 154.

第142行:

        $update = $dbh->do("UPDATE ${tablename}
                        SET ${jobStatus}='${newStatus}' 
                        WHERE id = '$$result{'id'}'");

第154行:

 print "Successfully created $$result{'databaseName'}\n";

我认为问题来自函数调用,因为如果我注释掉函数调用,一切都运行得很好!如果有人能帮我理解发生了什么,那就太好了。谢谢。附言:如果您注意到数据库中存储密码的安全问题,在这个问题得到正确解决之后会予以解决。= P Dylan
3个回答

2

您不希望存储从fetchrow_hashref返回的$result引用,因为每个后续调用都将覆盖该引用。

没问题,当您通过值传递数据时,在调用generate_config时不使用引用。

您是否在generate_config和调用函数中使用相同的$result变量?您应该在generate_config中使用自己的“my $result”。

      while ( my $result = $select->fetchrow_hashref() )
      #       ^^  #add my

根据你提供的代码片段,以上就是所有能够说的。

进行一些清理:

  1. When calling generate_config you are passing by value, not by reference. This is fine.
  2. you are getting an undef warning, this means you are running with 'use strict;'. Good!
  3. create lexical $result within the function, via my.
  4. While $$hashr{key} is valid code, $hashr->{key} is preferred.
  5. you're using dbh->prepare, might as well use placeholders.

    sub generateConfig {
      my($inName, inPass, $inExt) = @_;
    
      my $goodData = 1;
      my $select   = $dbh->prepare("SELECT id FROM $databasesTableName WHERE name = ?");
      my $insert   = $dbh->prepare("
                        INSERT INTO $configTableName(
                          databaseID
                          ,username
                          ,password
                        ,path) 
                        VALUES( ?, ?, ?, ?)" );
      my $path     = $documentRoot . $inName . "_config." . $inExt;
      $select->execute( $inName );
    
      if ($select->rows < 1 ) {
            $goodData = 0;
      }
    
      while ( my $result = $select->fetchrow_hashref() )
      {
        insert->execute( $result->{id}, $inName, $inPass, $path );
      }
    
     return 1;
    

    }


非常感谢。问题出在我在 generateConfig 函数中再次使用了 $result!我完全忽略了这一点!我还会实现你建议的其他一些东西。正如你可能注意到的那样,我刚开始学 Perl。再次感谢!同时也感谢其他所有人,你们的帖子也很有帮助! - djswartz

0

编辑:阅读了您的评论后

我认为两个错误都与您使用$$result有关。如果$resultfetchrow_hashref的返回值,就像这样:

$result = $select->fetchrow_hashref()

那么正确的引用其值的方式应该是:

 print "Successfully created " . $result{'databaseName'} . "\n";

并且:

    $update = $dbh->do("UPDATE ${tablename}
                    SET ${jobStatus}='${newStatus}' 
                    WHERE id = '$result{'id'}'");

旧答案:

generateConfig 函数中,您可以使用以下语法传递一个引用:

generateConfig(\$result{'databaseName'},$newPassword, "php");

$$用于解引用字符串的引用;\会给你一个应用到它所应用的对象的引用)。

然后,在打印语句中,我会尝试:

 print "Successfully created $result->{'databaseName'}->{columnName}\n";

确实,fetchrow_hashref返回的是一个哈希表(而不是字符串)。

这应该解决一个问题。

此外,您正在使用名为$dbh的变量,但您没有显示它在哪里设置。它是全局变量,以便您可以在generateConfig中使用它吗?当执行generateConfig时,它是否已被初始化?


Sergio,感谢您的快速回复。当我尝试在传递 $result{'databaseName'} 时使用 '' 替换 '$' 时,我会得到以下错误(我已经尝试过这个方法):Global symbol "%result" requires explicit package name at ./dbcreator.pl line 127.此外,$dbh 是全局变量。但是在您提到它之后,我将其作为第四个参数传递给 generateConfig。似乎没有改变任何东西。Dylan - djswartz
抱歉,我是 Stack Overflow 的新手。正在努力弄清楚界面...有没有一种方法可以回复更多的空间来正确格式化文本等? - djswartz
Sergio,我认为你在第一部分过于深思熟虑了。如果他想将外部的 $result 的某个部分传递到函数中,他应该像你在内部函数中让他做的那样,使用 $result->{'databaseName'} - Mark
@sergio $dbh 是与 CPAN 模块 DBI.pm 相关联的常用变量名。my $dbh = DBI->connect(......); 返回一个数据库句柄。随着语句准备好被执行,句柄被使用:my $sth = $dbh->prepare(.....); $sth->execute(...); - DavidO

0
当我从Oracle结果集运行hetchrow_hashref时,这让我疯狂。结果发现列名总是以大写形式返回。因此,一旦我开始引用大写的列,问题就解决了: insert->execute( $result->{ID}, $inName, $inPass, $path );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接