Reputation: 421
I am migrating my PHP web application to use namespaces in preparation for putting it up on GitHub. Most of this is straightforward, but I have one spot where the code must obtain static information from a class when the name of the class is provided by a string, and I cannot find the correct syntax for this situation:
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;
What is the correct syntax for referencing a static member of a class within a namespace when the name of the class is provided in a variable? The output of a web page that invokes the above code is:
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
The above code is in the base class Genealogy\Record which is implemented in "Genealogy/Record.inc". This base class is defined:
<?php
namespace Genealogy;
use \PDO;
use \Exception;
use \ArrayAccess;
use \Countable;
use \Iterator;
class Record implements Iterator, ArrayAccess
{
...
protected static $defaultOrder = '';
The derived class Genealogy\Blog is implemented in "Genealogy/Blog.inc" as follows:
<?php
namespace Genealogy;
use \PDO;
use \Exception;
require_once __NAMESPACE__ . '/Record.inc';
print "<p>Blog.inc included</p>\n";
class Blog extends Record
{
...
The class Blog does not override the base definition of static member $defaultOrder.
FYI I converted the code of the library to use namespaces by running the following PERL script:
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;
}
I do not believe it is significant but the web site is running PHP Version 7.2.10.
The classes in this library implement an object-oriented interface to an SQL database. That is the application code accesses fields within the record using sub-script notation and updates the record by $record->save() which determines whether or not to use INSERT or UPDATE to apply the change and uses the proper syntax for the SQL server. The RecordSet class that appears in the exception encapsulates an SQL query and presents the appearance of an array of instances of Record and permits performing updates and deletes of all of the members of the set. These two classes, and the classes that are derived from them to support individual tables, completely insulate the application code from SQL.
Upvotes: 1
Views: 99
Reputation: 421
The problem I was having would appear to be that the :: operator was processed before the concatenation. When I changed the code to:
$nsclass = __NAMESPACE__ . "\\" . $className;
if (!class_exists($nsclass))
{
include __NAMESPACE__ . "/" . $className . ".inc";
}
$order = $nsclass::$defaultOrder;
it worked.
Upvotes: 1