Autoload Obscurity - php

I"m sorry now but I don't know if I can get all the details possible to make an educated guess on what exactly is going on.
I'm trying to check to see if a class exists, if it doesn't I need to create the class. Some classes have sub classes (namespaces).
namespace {
class wattsjus {
}
}
namespace wattsjus {
class OtherClass {
}
}
so whether I __autoload wattsjus or wattsjus\OtherClass I'm loading both classes.
I can tell that up until the point I load the classes they are not there if I try and autoload the 'inner class'. After I load the class I get an error that the class is already loaded. Yet I can print text just before that point and that line is never reached.
I am using class_exists to make sure the wattsjus class is not loaded. Before I load the class this is true (loaded). yet if I try to make an instance of wattsjus it cannot be found.
I'm using the following code to check where the class was created and it's stating a line number that is never reached at this point. I have an print statement before this line to be sure.
$reflector = new ReflectionClass('wattsjus');
echo $reflector->getFileName();
A great mystery to me as to how code could have been reached without executing the previous line.
Edit, Warning this is ugly code:
function __autoload($class_name) {
echo 'in';
$parts = explode('\\',$class_name);
if($class_name == $_GET['u5u'] || $parts[0] == $_GET['u5u']) {
$cl = class_exists($_GET['u5u'], false);
echo $cl ? 'yes' : 'no';
if(!$cl) {
if($_GET['e5e'] != 'Prod') { $env = $_GET['e5e']; }
$q = "SELECT f.`Name`, f.`$env"."ParameterList` `ParameterList` FROM `Function` f WHERE f.UserId = ".SiteUserId." AND `Status` = 'A' ORDER BY INSTR(f.`Name`, '\\\\') > 0, f.`Name`";
$results = DataObject::GetDBObject()->Query($q, 'wattsjus_json');
$class = "namespace { class $_GET[u5u] {";
$class .= GetFunctions($results);
$class .= '}}';
echo 'I\'m not here yet';
eval($class);
} else {
$reflector = new ReflectionClass('wattsjus');
echo $reflector->getFileName();
}
here the output that is produced trying to get OtherClass is:
inyes/home4/wattsjus/public_html/ajson/global_base.php(25) : eval()'d code<br />
<b>Fatal error</b>: Class 'wattsjus\OtherClass' not found in <b>/home4/wattsjus/public_html/ajson/global_base.php(112) : runtime-created function</b> on line <b>1</b><br />
so to me this is saying that the class wattsjus already exists which should include OtherClass in the namespace. Though it cannot be found. If I let it keep going and create wattsjus again it will say the class has already been defined. Very confusing I know.

I changed the structure of the classes to use "namespace wattsjus\OtherClass" rather than make a OtherClass class and for some reason PHP is less confused by this. Really weird glitch/bug I'd have to say.
namespace {
class wattsjus {
}
}
namespace wattsjus\OtherClass {
}

Related

Why the "use" command in PHP not working with include?

I have this script:
<?php
error_reporting(E_ALL);
require 'vendor/autoload.php';
use Church\Config;
use Church\SQLiteConnection;
use Church\Template;
use Church\User;
$ERROR = "";
if(isset($_POST['username']) && isset($_POST['username']))
{
$login = new User((new SQLiteConnection())->connect());
if($login->loginUser($_POST['username'], $_POST['password']))
{
}
else {
$ERROR = "login";
}
}
if(isset($_GET['go']))
{
}
else {
if (!file_exists(Config::PATH_TO_SQLITE_FILE)) {
include('init/install.php');
}
}
When I make it with this part:
include('init/install.php');
instead of this:
$tpl = new Template('templates/install.tpl');
$tpl->set('HEADER', $tpl->getFile('templates/header.tpl'));
$tpl->set('FOOTER', $tpl->getFile('templates/footer.tpl'));
$tpl->set('APP_NAME', Config::APP_NAME);
$tpl->set('APP_VERSION', Config::APP_VERSION);
$tpl->set('BASE_URL', $_SERVER['PHP_SELF']);
$tpl->render();
I get this error:
Fatal error: Uncaught Error: Class 'Template' not found in
I do not understand why it is working without include but with include is the auto loading not working. What did I miss?
Take a look at the docs here: https://www.php.net/manual/en/language.namespaces.importing.php
The use keyword must be declared in the outermost scope of a file (the global scope) or inside namespace declarations. This is because the importing is done at compile time and not runtime, so it cannot be block scoped. The following example will show an illegal use of the use keyword:
And then:
Importing rules are per file basis, meaning included files will NOT inherit the parent file's importing rules.
The conclusion is that you can't do what you want to do. You need to import (aka use) in your included file too.

class_exists when autoload flag is false

So, as part of a project, I was considering building a flagging system. The idea behind this would be a cron job that runs daily to determine whether each of a series of flags still applied to a specific object (and if so, save that flag data for the object).
// code stub
$flags = $this->getFlags();
foreach($flags as $flag)
{
$className = 'Svc_Flags_'.$flag->flag_code;
if(class_exists($className, false)
{
(new $className())->setFlag();
}
}
And right now, in the dummy code for that class, I have a constructor that echos a simple text message, and the function setFlag() that echos a different text message.
<?php class Svc_Flags_Test extends Svc
{
public function __construct()
{
echo 'construct<br/>';
}
public function setFlag()
{
echo 'set flag<br/>';
}
}
Now, this doesn't work. By that, I mean that I am not seeing either echo.
However, if I do this:
// code stub
$flags = $this->getFlags();
foreach($flags as $flag)
{
$className = 'Svc_Flags_'.$flag->flag_code;
(new $className())->setFlag(); // This is the added line of code
if(class_exists($className, false)
{
(new $className())->setFlag();
}
}
I get the constructor echo, and the setFlag() echo TWICE.
Why is this happening? Now, I'm pretty sure I could just wrap part of this in a try/catch block to get past any errors if a class isn't there, but I'm curious as to why it doesn't seem to find the class unless I explicitly call it before the if statement.

Namespaced class not found

I have the following which works just fine:
use frontend\models\modules\shipping\Usps;
$shipping = new Usps;
If however I use the following it throws the error: Class 'Usps' not found
use frontend\models\modules\shippingl\Usps;
I am loading classes dynamically, thus I cannot use the namespace when calling new $class, eg. I might also have:
use frontend\models\modules\payment\Usps;
$class = 'Usps';
$shipping = new $class;
How can I make this work using a variable? If I don't use namespaces/autoload and just include the class file it works just fine.
This question is not a duplicate, the referenced question/answers do not declare a 'use'.
This is the only way I see this working without security issues and tons of errors, especially if $class coming from user input.
I added a "Ups" class so it makes a little more sense.
use frontend\models\modules\payment\Usps;
use frontend\models\modules\payment\Ups;
if($class == 'Usps') {
$shipping = new Usps;
} else if($class == 'Ups') {
$shipping = new Ups;
} else {
// No valid class found - handle accordingly
}

Using namespace in if / else statements

I am manipulating the same file to manage two external api classes.
One api class is based on namespaces, the other one is not.
What I would like to do is something like this:
if($api == 'foo'){
require_once('foo.php');
}
if($api == 'bar'){
require_once('bar.php');
use xxxx\TheClass;
}
The problem is that when I do so, the following error message is returned:
Parse error: syntax error, unexpected T_USE in etc...
Question 1: Do I have to use two different files to manage the two classes or is it possible to manage both while using namespaces in the document? From what I see, it does not seem to be.
Question 2: Why namespaces could not be used inside if() statements?
Thank you for your help
Please see Scoping rules for importing
The use keyword must be declared in the outermost scope of a file (the global scope) or inside namespace declarations. This is because the importing is done at compile time and not runtime, so it cannot be block scoped.
All use does is import a symbol name into the current namespace. I would just omit the import and use the fully qualified class name, eg
switch ($api) {
case 'foo' :
require_once('foo.php');
$someVar = new SomeClass();
break;
case 'bar' :
require_once('bar.php');
$someVar = new \xxxx\TheClass();
break;
default :
throw new UnexpectedValueException($api);
}
You can also simply add the use statement to the top of your script. Adding it does not commit you to including any files and it does not require the symbol to be known, eg
use xxxx\TheClass;
switch ($api) {
case 'foo' :
require_once('foo.php');
$someVar = new SomeClass();
break;
case 'bar' :
require_once('bar.php');
$someVar = new TheClass(); // imported above
break;
default :
throw new UnexpectedValueException($api);
}
Use statements should be placed before any executable code (you can have namespaces, classes, functions and constants definitions). Actually it can, just have to be placed unconditionally in some namespace, so no ifs or inside functions. Also don't be afraid of putting use at the top, it does not load any class or instantiate object. it acts only as alias that is used when encountered later during execution.
As for having them in one file, it is possible to have many namespaces and even global namespace in one file:
<?php
namespace
{
class myclass{}
}
namespace mynamespace
{
class myclass{}
}
But I strongly discourage such "management" of code. Each class should have it's own file.
Alright, just confirming what i said was true.. Try something like this :
*Test_1.php*
$API = "test_1";
if ($API === "test"){
}elseif ($API === "test_1"){
require ("test.php");
$API = new daryls\testt;
}
$API->test();
test.php
namespace daryls;
class testt {
public function test(){
echo "Started";
}
}
Running this has worked without a hitch
Another option for API class versioning is to set the classname as a variable conditionally.
// Get class name
switch ($api_version) {
case 'v0':
// No class namespace
$class = 'Handler';
break;
case 'v1':
// Namespaced class
$class = 'API\App\v1\Handler';
break;
case 'v2':
// Namespaced class
$class = 'API\App\v2\Handler';
break;
default:
throw new Exception('Unknown API version: ' . $api_version);
}
// Get class object
$handler = new $class();

PHP "Helper Class" - Class not found

I am having an issue that coming from PHP 5.3.2 to 5.3.3 the code no longer can find the "I2A2" class.
Here is some info:
Error:
ErrorException [ Error ]: Class 'I2A2' not found
Fatal error: Class 'I2A2' not found in /var/www/html/root/sandbox/lpolicin/t6/fuel/app/classes/observer/selectcustomer.php on line 6
$directory_listing = \I2A2::get_customer_info("puid",$customer->puid);
Code:
"classes/observer/selectcustomer.php "
class Observer_Selectcustomer extends Orm\Observer
{
public function after_load(Model_Customer $customer)
{
$directory_listing = \I2A2::get_customer_info("puid",$customer->puid);
}
}
"classes/I2A2.php"
class I2A2
{
if (static::$initalized === true)
{
return;
}
}
Auto loader (this is insert into a huge array then auto loads everyting)....
{
'always_load' => array(
'classes' => array(),
}
If you need more info please let me know!
Check your paths: the first is correctly fully lowercase but the second suddenly has the filename uppercase. All paths in Fuel are fully lowercase, no matter the classname. Thus change the filename for the I2A2 class to i2a2.php and it'll work.

Categories