Fatal error while extending a class which does not have namespace - php

I have two classes, Database and States. The class Database has no namespace assigned. The class States, written in file states.php, has a namespace assigned as below:
namespace Resources;
require_once 'database.php';
$states = new States();
echo $states->readAll();
class States extends Database{
private $db;
public function __construct(){
$this->db = new Database();
}
function readAll(){
return $this->db->Execute('SELECT * FROM states;');
}
}
If I enter the url http://localhost/mydomain/objects/states.php which should instantiate the class and show list of states, an error is thrown as:
Fatal error: Uncaught Error: Class 'Resources\Database' not found in
C:\xampp\htdocs\mydomain\objects\states.php on line 5
If I remove the line namespace Resources; the code runs.
I have recently decided to implemen namespaces in my website, so most likely, I am doing something wrong.
Any help please?

The PHP manual has a section introducing namespaces which is well worth reading. In particular, have a look at this page drawing the analogy to a file system:
The same principle can be applied to namespaced elements in PHP. For
example, a class name can be referred to in three ways:
Unqualified name, or an unprefixed class name like $a = new foo(); or foo::staticmethod();. If the current namespace is currentnamespace,
this resolves to currentnamespace\foo. If the code is global,
non-namespaced code, this resolves to foo.
Qualified name, or a prefixed class name like $a = new subnamespace\foo(); or subnamespace\foo::staticmethod();. If the
current namespace is currentnamespace, this resolves to
currentnamespace\subnamespace\foo. If the code is global,
non-namespaced code, this resolves to subnamespace\foo.
Fully qualified name, or a prefixed name with global prefix operator like $a = new \currentnamespace\foo(); or
\currentnamespace\foo::staticmethod();. This always resolves to the
literal name specified in the code, currentnamespace\foo.
In your example, Database is an "unqualified name", so point 1 applies. The current namespace is Resources, so it refers to Resources\Database. If you remove the namespace Resources; line, the code becomes "global, non-namespaced code", so it refers to just Database.
To refer to the class Database when the current namespace is Resources, you can use a "fully qualified name", as described in point 3. So in this case, you would write class States extends \Database.
There are other ways to write it, such as adding use statements to import/alias a name, but there's no point me copying the whole PHP manual here.

Related

spl_autoload_register couldn't get "use" namespace

#file1
spl_autoload_register(function($class){
require_once "{$class}.php";
});
new classes\Foo();
#file2
namespace classes;
class Foo implements toolInterface {
function __construct(){
echo __CLASS__;
}
public function tool(){
}
}
I have a problem with spl_autoload_register, above example works fine, but when I try to use use classes it will have fatal error, anyone know how to solve this problem?
//fatal error
spl_autoload_register(function($class){
require_once "{$class}.php";
});
use classes;
new Foo();
The ability to refer to an external fully qualified name with an alias
Note that for namespaced names (fully qualified namespace names
containing namespace separator, such as Foo\Bar as opposed to global
names that do not, such as FooBar), the leading backslash is
unnecessary and not recommended, as import names must be fully
qualified, and are not processed relative to the current namespace.
PHP: Using namespaces: Aliasing/Importing
So we need the fully qualified name
use classes\Foo;
new Foo();
If you log the $class variable provided to the closure you have you'll note that the FQCN (Fully Qualified Class Name) is given. In your case:
classes\Foo
You will need to ensure the file path is correct for that.
Or you could also use the de-facto standard - Composer - Don't mind the fact that the home page has a picture of a conductor.

Instantiate a PHP stdClass in my namespace – fatal error

I want to write a small add on for an existing CMS. To do so, I need to extend a class from that CMS' code.
My code will be written inside its own namespace, while the CMS' code does not use namespacing, which basically means it exists inside the global namespace.
Inside my code, I create a new stdClass:
$var = new stdClass();
With that code is place, it always produces a fatal error:
Fatal error: Class 'MyNamespace\something\StdClass' not found in /some/rather/long/path/to/class.php on line 123
Creating the stdClass like this solves that problem:
$var = new \stdClass();
Since I am still pretty new to namespaces, I am not exactly sure what the problem here is?
My guess is that in the first example, the stdClass would be created in the namespace of my class. This actually means the constructor of a class called stdClass existing in my namespace would be called, but since that class does not exist, an error is thrown.
In the second example, I signalize that I want to instantiate the class called stdClass from the global namespace, which somehow suddenly makes sense.
If anyone could elaborate what is happening here I would be very happy.
You appear to understand the concept behind namespaces, and you are headed in the right direction on your analysis of what is happening.
When you are working inside of a namespace you are able to refer to names as unqualified, qualified, and fully qualified.
When you make a namespace you are telling PHP to organize (and resolve) the names of your classes, function, methods, etc. away from the same scope where the built-in PHP code lives along with any other code behind its own namespace. It is away to organize your code and avoid naming collisions among libraries and built-in PHP functions.
Here is a brief on how names get resolved:
If you are trying to resolve a name within the same namespace you can use the unqualified name. So for class \Foo\Bar\Baz you can use new Baz(); as long as you are in namespace \Foo\Bar.
If you are trying to resolve a name that is lower in the same parent namespace you can use the qualified name. So for class \Foo\Bar\Baz you would need to use new Bar\Baz(); if you were in namespace \Foo.
If you are trying to resolve a name that is not in your namespace or is in the global namespace (built-in PHP stuff) then you must use the fully qualified name. If you are in namespace \Foo\Bar and you want to make use of something like the mysqli class you would need to call it by its fully qualified name. e.g. new \mysqli() Your question above is a perfect example that illustrates this. Likewise, if you need to access a class in a totally different namespace you would also need the fully qualified name: new \Third\Party\AppClass();
So to summarize, you are right, the built-in stdClass does not exist in your namespace, therefore you need to access it by the fully qualified name. The reason you must do thing this way had to do with conforming to the rules PHP uses when resolving names.
If you ever need to find out what namespace you are in it will be in the __NAMESPACE__ constant.
In case you haven't already read it, here is the documentation on name resolution in PHP: http://php.net/manual/en/language.namespaces.rules.php
The code is evaluated in your namespace and stdClass doesn't exist there. You are effectively answering your own question with your guess.
Your guess is correct. Look at the comments in "class references" section of Example #1 on this page.
http://php.net/manual/en/language.namespaces.rules.php

Unrecognized namespace alias causing unexpected invocation of autoloader

I am attempting use a namespace alias to invoke static behavior on a class. The class has already been loaded, and I think I've got its alias defined properly. When I attempt to use that alias, however, php attempts (and fails) to autoload the class. I'm running php 5.3.3, and ZendFramework 1.8.4, all under CentOS 5.9.
Am I doing something wrong?
Here's are some (sanitized) code excerpts (my employer won't allow me to share the actual code, sorry).
<?php
// Filename = 'SomeAssembly/AbstractFoo.php'
namespace SomeAssembly;
use BaseAssembly\Base;
use SomeAssembly\ConcreteFoo;
require_once 'BaseAssembly/Base.php';
require_once 'SomeAssembly/ConcreteFoo.php';
class AbstractFoo extends Base {
// ...
static public function buildFooNamed_($aFooName) {
// ...
$declaredClasses = get_declared_classes();
$namespace = __NAMESPACE __;
$answer = $aFooName::create(); // Invokes autoloader!
return $answer;
}
}
?>
When I invoke AbstractFoo::buildFooNamed_('ConcreteFoo'), the autoloader is invoked. It fails because "ConcreteFoo" does not include the namespace.
When I set a breakpoint at "$answer = $aFooName::create", I see that $declaredClasses includes 'SomeAssembly\ConcreteFoo' and $namespace = 'SomeAssembly".
I think I declared the namespace alias "ConcreteFoo" in the line that reads "use SomeAssembly\ConcreteFoo".
Why isn't "ConcreteFoo" recognized as a namespace alias of a loaded class? If so, why is the autoloader being invoked?
It seems that my question has been answered in Dynamic namespaced class with alias.
From the manual:
Importing is performed at compile-time, and so does not affect dynamic class, function or constant names.
So I have to collect the fully-qualified class name myself. Oh well.

PHP Namespaces & Referencing Classes not contained within Namespaces

I have a simple question, which should hopefully have a quick answer. The code I have written makes heavy use of namespaces (I use fully qualified names everywhere); however, a piece of code (a calendar / date picker control, not written by myself) needs to be included. When I attempt to create the control, it assumes the current namespace (GUI), resulting in this error: "PHP Fatal error: Class 'GUI\tc_calendar' not found in C:\inetpub\wwwroot\Calico\calico_classes_v2.php on line 1852". Now, the calendar control itself (and it's underlying class file) does not make use of namespaces, and I am a little worried about attempting to modify it (an earlier attempt did not go well).
How can I import / include a control, that is not contained within a namespace, into the rest of my code, that does? Does PHP have something like "Import class calendar from file AS \Calendar\Calendar"?
Edit:
For additional information: I have a class, called "tc_calendar", contained in a file called "tc_calendar.php". It is not part of any namespace.
In a separate file, I have several classes (Bitmap, CompositeCalendar, EventEditor, TimeExtractor), all contained within their appropriate namespaces (GUI, Data, Extract, etc.).
In one of those classes, CompositeCalendar, contained within the GUI namespace, I am trying to create an instance of a tc_calendar. However, PHP is throwing an error (above). tc_calendar is not a part of any namspace (and definitely not a part of the GUI namespace, which PHP is just assuming, because it can't seem to find it), and I need help creating an instance of it.
tldr; $newcontrol = new tc_calendar() doesn't work; PHP tries to guess the namespace for it (because one isn't specified, because tc_calendar isn't a part of any namespace), comes up with \GUI\tc_calendar (obviously wrong). How do I access a class, not contained within a namespace, from inside a namespace?
Do you mean something like this:
namespace GUI;
use \tc_calendar as Calendar;
$myCalendar = new Calendar();
The as Calendar is optional. You could aswell keep it with the original name tc_calendar if you ommit the as Calendar.
Update
To put it in shape of the comment:
namespace {
class tc_calendar {}
}
namespace GUI {
use \tc_calendar;
class CompositeCalendar {
private function blah() {
$control = new tc_calendar();
$control->stuff();
}
}
}
I wouldn't copy paste external libraries into he same file though. It bad practise. It is better to keep them in another file and then include them and have the following:
namespace GUI;
use \tc_calendar;
require_once 'tc_calendar.php';
class CompositeCalendar {
private function blah() {
$control = new tc_calendar();
$control->stuff();
}
}
Or combine my 3 snippets to have it any other form you like.
Also I would suggest to extend the calendar if you are just building calendar class based on the the tc_calendar:
namespace GUI;
use \tc_calendar;
require_once 'tc_calendar.php';
class CompositeCalendar extends tc_calendar {
private function blah() {
$this->stuff();
}
}
Any class not in a namespace is automatically in the global namespace.
To refer to anything in the global namespace from anywhere, use a single preceding \:
new \tc_calendar;

PHP namespace with Dynamic class name

Wondering if anyone else has encountered this problem when utilizing the new ability to namespace classes using PHP 5.3.
I am generating a dynamic class call utilizing a separate class for defining user types in my application. Basically the class definer takes an integer representation of types and interprets them, returning a string containing the classname to be called as the model for that user.
I have an object model for the user's type with that name defined in the global scope, but I have another object with the same name for the user's editor in the Editor namespace. For some reason, PHP won't allow me to make a namespaced dynamic call as follows.
$definition = Definer::defineProfile($_SESSION['user']->UserType);
new \Editor\$definition();
The identical syntax works for calling the global basic object model in the global namespace and I use it this way reliably throughout the application.
$definition = Definer::defineProfile($_SESSION['user']->UserType);
new $definition();
This will correctly call the dynamically desired class.
Is there a reason the two would behave differently, or has dynamic calling for namespaces not been implemented in this manor yet as this is a new feature? Is there another way to dynamically call a class from another namespace without explicitly placing its name in the code, but from within a variable?
Well, just spell out the namespace in the string:
$definition = Definer::defineProfile($_SESSION['user']->UserType);
$class = '\\Editor\\' . $definition;
$foo = new $class();
And if it's a child namespace (as indicated in the comments), simply prepend the namespace with __NAMESPACE__:
$class = __NAMESPACE__ . '\\Editor\\' . $definition;
So if the current namespace is \Foo\Bar, and $definition is "Baz", the resulting class would be \Foo\Bar\Editor\Baz

Categories