无法使用PHP名称空间将Class给定名称解析为字符串

时间:2019-01-06 23:30:37

标签: php

我正在迁移PHP Web应用程序以使用名称空间,以准备将其放置在GitHub上。大部分都是简单明了的,但是我有一个地方,当类名由字符串提供时,代码必须从类中获取静态信息,而我无法找到这种情况的正确语法:

if ($className == '')
{
    $className          = 'Record';
    $information['classname']   = 'Record';
}
if (!class_exists(__NAMESPACE__ . "\\" . $className))
    {
        print "<p>include '". __NAMESPACE__ . "/" . $className . ".inc'</p>\n";
        include __NAMESPACE__ . "/" . $className . ".inc";
    }

    // BOTH of the following statements report Class 'Blog' not found
    // when $className == "Blog"
$order  = $className::$defaultOrder;
$order  = __NAMESPACE__ . "\\" . $className::$defaultOrder;

在变量中提供类名称时,引用名称空间中类的静态成员的正确语法是什么?调用上述代码的网页的输出为:

include 'Genealogy/Blog.inc'
Blog.inc included
Fatal error: Uncaught Error: Class 'Blog' not found in /home/jcobban/includes/Genealogy/Record.inc:2043 Stack trace: #0 /home/jcobban/includes/Genealogy/RecordSet.inc(418): Genealogy\Record::getInformation('Blogs') #1 /home/jcobban/includes/Genealogy/Template.inc(2898): Genealogy\RecordSet->__construct('Blogs', Array) #2 /home/jcobban/includes/Genealogy/Template.inc(764): Genealogy\FtTemplate->customization() #3 /home/jcobban/public_html/Genealogy/genealogy.php(82): Genealogy\Template->__construct('/home/jcobban/p...') #4 {main} thrown in /home/jcobban/includes/Genealogy/Record.inc on line 2043

上面的代码在基类Genealogy \ Record中,该基类在“ Genealogy / Record.inc”中实现。定义此基类:

<?php
namespace Genealogy;
use \PDO;
use \Exception;
use \ArrayAccess;
use \Countable;
use \Iterator;
class Record implements Iterator, ArrayAccess
{
...
protected static    $defaultOrder   = '';

派生类Genealogy \ Blog在“ Genealogy / Blog.inc”中实现如下:

<?php
namespace Genealogy;
use \PDO;
use \Exception;
require_once __NAMESPACE__ . '/Record.inc';
print "<p>Blog.inc included</p>\n";
class Blog extends Record
{
...

Blog类不会覆盖静态成员$ defaultOrder的基本定义。

仅供参考,我通过运行以下PERL脚本将库的代码转换为使用名称空间:

use strict;
use warnings;
use 5.010;

use File::Find;
use File::Slurp;

my @content;
find( \&wanted, '/home/jcobban/includes/');

exit;

sub wanted {
  if ((substr $File::Find::dir, -9) ne "Genealogy" && -f)
  {
    print "wanted: ",  $File::Find::name, "\n";
my @lines   = read_file($File::Find::name);
my $first   = shift @lines;
if ((substr $first, 0, 5) eq '<?php')
{
    foreach my $line (@lines){
    $line   =~ s#require_once(\s*)(['"])#require_once$1__NAMESPACE__ . $2/#;
    $line   =~ s#require(\s*)(['"])#require$1__NAMESPACE__ . $2/#;
    $line   =~ s#include(\s*)(['"])#include$1__NAMESPACE__ . $2/#;
    $line   =~ s#include(\s*)\$#include$1__NAMESPACE__ . "/" . \$#;
    $line   =~ s#class_exists\((['"])#class_exists(__NAMESPACE__ . $1\\\\#;
    $line   =~ s#class_exists\((\$)#class_exists(__NAMESPACE__ . "\\\\" . $1#;
    }
    my $newfile = $File::Find::dir . "/Genealogy/" . $_;
    print "add namespace and write to $newfile\n";
    unshift @lines, "use \\Iterator;\n";
    unshift @lines, "use \\Countable;\n";
    unshift @lines, "use \\ArrayAccess;\n";
    unshift @lines, "use \\Exception;\n";
    unshift @lines, "use \\PDO;\n";
    unshift @lines, "namespace Genealogy;\n";
    unshift @lines, $first;
    write_file($newfile, @lines);
}
  }
  return;
}

我认为这并不重要,但该网站运行的是PHP版本7.2.10。

该库中的类实现了SQL数据库的面向对象的接口。也就是说,应用程序代码使用子脚本符号访问记录中的字段,并通过$ record-> save()更新记录,该记录确定是否使用INSERT或UPDATE来应用更改并为SQL Server使用正确的语法。出现在异常中的RecordSet类封装了一个SQL查询,并显示了Record实例数组的外观,并允许执行该集合的所有成员的更新和删除。这两个类以及从它们派生出来的用于支持单个表的类将应用程序代码与SQL完全隔离。

1 个答案:

答案 0 :(得分:0)

我遇到的问题似乎是::运算符在连接之前已处理。当我将代码更改为:

$nsclass                = __NAMESPACE__ . "\\" . $className;
if (!class_exists($nsclass))
{
    include __NAMESPACE__ . "/" . $className . ".inc";
}
$order                  = $nsclass::$defaultOrder;

有效。