Class not found (in PHP) - php

This code works without problems:
<?php
namespace NamespaceA;
class A extends \NamespaceB\B {}
namespace NamespaceB;
class B {}
But why the following code cause Fatal error: Class 'NamespaceB\B' not found in ...file?
<?php
namespace NamespaceA;
class A extends \NamespaceB\B {}
namespace NamespaceB;
class B extends \NamespaceC\C {}
namespace NamespaceC;
class C {}
And this code also works without problems:
<?php
namespace NamespaceA;
class A extends \NamespaceB\B {}
namespace NamespaceC;
class C {}
namespace NamespaceB;
class B extends \NamespaceC\C {}
UPD:
Without any namespace, also Fatal error: Class 'B' not found in ...file:
<?php
class A extends B {}
class B extends C {}
class C {}
Works without problems:
<?php
class A extends B {}
class B {}

http://php.net/manual/en/keyword.extends.php
Classes must be defined before they are used. If you want the class A to extend the class B, you will have to define the class B first. The order in which the classes are defined is important.
Edit:
Found more:
Fatal error when extending included class
After some research, it became clear, that actually you can use a class before declaring it. But, declaration of the class and all parent classes must be in the same file.
So if you declare a parent class in one file and a child class in another, it won't work.
Also, you must declare parent classes first. After that you can extend them.
Edit Number 2:
Okay so I did some more research on the issue. There is probably some internal implementation detail that currently allows for the one case to work (my guess would be something regarding auto-loading) however this is something that could change at any time and should never be relied upon.

First use include_once() to add all the files in your index file and when your are extends to any class, instantiate that parent class first.Example:
index.php-->
<?php
include_once('parentClass.php');
include_once('childClass.php');
$parentObj = new parent();
$childObj = new child();
?>
child.php-->
<?php
class child extends parent{
function __construct(){
}
}
?>

Related

Order of PHP class extensions in a single file

In some cases defining PHP class extensions out of order causes a fatal error, and in some cases it doesn't. I'm trying to understand the underlying behavior.
For example, both
<?php
class BaseClass {}
class FirstExt extends BaseClass {}
and
<?php
class FirstExt extends BaseClass {}
class BaseClass {}
are fine, so it's not the case that simply defining subclasses out of order causes a problem.
However, errors arise when there are three classes involved, but only in one specific case, namely when the chain of classes is defined in reverse order. That is, the following code results in a fatal error:
<?php
class SecondExt extends FirstExt {}
class FirstExt extends BaseClass {}
class BaseClass {}
If you try to run this from the command line (say as main.php), you get
PHP Fatal error: Class 'FirstExt' not found in /path/to/main.php on line 2
However, any of the other five orderings of the three classes run with no errors. I was quite surprised that even
<?php
class SecondExt extends FirstExt {}
class BaseClass {}
class FirstExt extends BaseClass {}
works fine. The distinguishing factor is that all three possible pairs of classes are out of order in the case that gives an error, whereas in all the other cases at most two of the three pairs are out of order.
What is going on under the hood to produce this behavior?
The behavior isn't intuitive, but I don't think it's a bug, it's just an effect of the way PHP loads classes.
In order for a class to extend a parent class, the parent class must already be defined when the child class is defined.
Based on my observations, it appears that after the file is parsed and execution begins, the following classes are defined:
built-in classes
all user-defined classes defined before the file was parsed
user-defined base classes in that file
user-defined classes in that file that extend another class already defined, either earlier in that file or before that file was parsed
Basically any class that can be defined at compile time will be, and any other classes not defined at that point will be (attempted to be) defined at run time.
So in this example:
<?php
echo class_exists('A') ? "Yes" : "No"; // No
echo class_exists('B') ? "Yes" : "No"; // Yes
echo class_exists('C') ? "Yes" : "No"; // Yes
class A extends B {}
class C {}
class B extends C {}
class B is defined when class A tries to extend it, because it was defined when the file was parsed, because class C was defined before it in the file.
But in this example:
<?php
echo class_exists('A') ? "Yes" : "No"; // No
echo class_exists('B') ? "Yes" : "No"; // No
echo class_exists('C') ? "Yes" : "No"; // Yes
class A extends B {}
class B extends C {}
class C {}
class B is not defined when class A tries to extend it, because it was not defined when the file was parsed, because class C was not defined before it in the file.
PHP tries to find it, but it's not going to check in the same file again, it's going to try to autoload it. That's when you get "not found".
Add a fourth class and you can see it doesn't only happen when the classes are defined in reverse order:
echo class_exists('A') ? "Yes" : "No"; // No
echo class_exists('B') ? "Yes" : "No"; // No
echo class_exists('C') ? "Yes" : "No"; // Yes
echo class_exists('D') ? "Yes" : "No"; // Yes
class A extends B {}
class D {}
class B extends C {}
class C extends D {}

How to use namespace in a parent class constructor

I have a class named Service_B which extends a custom service class.
This custom service class requires one single object named Reader in its __construct() in order to instantiate properly.
The parent service is defined as follow
namespace Vendor\Services;
abstract class Service{
function __construct(Vendor\Services\Reader $reader){
}
}
Service_B is defined as follow:
namespace Vendor\Services;
class Service_B extends Service{
function __construct(){
parent::__construct(new \Vendor\Services\Reader());
}
}
Reader do have the following line at the top of the file:
use Vendor\Services;
Class files are organized like this:
Vendor/Services/Service_B.php
Vendor/Services/Reader.php
Question:
When I instantiate Service_B, I get the following error message:
Fatal error: Class 'Vendor\Services\Reader' not found
I don't understand why I get this error since I think I am using the proper namespaces declarations. Thank you
On top of your Reader class place:
//This will declare the Reader class in this namespace
namespace Vendor\Services;
and remove:
//THIS IS A WRONG DIRECTIVE: you're telling PHP to use the Vendor\Services class but it doesn't even exist
use Vendor\Services;
Then modify the Service_B class as follow:
namespace Vendor\Services;
//i think this should extend Service, as it's calling the parent constructor
class Service_B extends Service
{
function __construct(){
parent::__construct( new Reader() );
}
}
This way all yours 3 classes will be in the same namespace, and the Reader class should be found without explicit namespace prefix

Are namespaces in PHP "inherited"?

EDIT:
Yes the problem was using \ at the beginning of the use statement. As M1ke pointed out, use goes from the root element.
Original post
I think is a PHP question but it may be Drupal.
I'm working on a headless Drupal project where is using a class (which I call Entity Model) that uses a Drupal class called EntityFieldQuery.
Before a create or use this class I bootstrap Drupal using:
require_once DRUPAL_ROOT.'/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
The entity model class is in the Models names space like so:
namespace Models;
use \EntityFieldQuery;
class EntityModel
{
.....
$query = new EntityFieldQuery();
$query->doSomething();
......
}
The EntityFieldQuery is found perfectly as I use the "\" because this class is out of the Models namespace.
The problem is when this class is created is uses other classes that don't use any namespace, and I have the following error:
class Models\InsertQuery not found in ....
Here is the class used by EntityFieldQuery that uses InsertQuery
class InsertQuery_mysql extends InsertQuery ...
I don't understand why InsertQuery_mysql is found but InsertQuery
I ended up adding a "\" in InsertQuery to fix the problem like so:
class InsertQuery_mysql extends \InsertQuery ...
Actually this class in a php file called query.inc that contains two defitinion classes (in the same file, I don't know this is a a problem too)
class InsertQuery_mysql extends InsertQuery
....
class TruncateQuery_mysql extends TruncateQuery
I thought that if I use "new \ClassName()" the "default namespace" inside this class would be "\" too and not the first called class's namespace.
I don't like to modify 3rd party libraries, is any way to avoid this? I guess is a architecture problem rather than a lack of definition if someone has a better idea, I appreciate.
Thanks!
EDIT2: Adding more info...
In order of execution.
index.php:
require_once 'vendor/autoload.php';
require_once DRUPAL_ROOT.'/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
...
app/SiteController.php:
use Models\Campaign;
class SiteController {
...
$campaing = new Campaign();
...
app/Models/Campaing.php:
namespace Models;
class Campaign extends EntityModel {
...
app/Models/EntityModel.php:
namespace Models;
use \EntityFieldQuery; //<-- this should go without \ as I say in EDIT section
class EntityModel {
...
public function getAll() {
$query = new EntityFieldQuery(); //<--throwed Models\InsertQuery not found. It must have \ at the beginning of the class name.
To answer the base question (and pending further code) PHP namespaces are set by whichever namespace is declared in the file.
// Bar.php
namespace Foo;
class Bar {}
// some other file
use Foo\Bar;
$test = new Bar(); //works
// different file
namespace Foo;
$test = new Bar(); // works
// another file
require 'Bar.php';
// won't work because we are not in namespace "Foo"
$test = new Bar();
In your specific case it the use \EntityLoader should be use EntityLoader because you're exiting the namespace you want to be inside.

Symfony2 extends Exception class

I'm working on a Symfony2 project. For useful technical pratictes, I need to import external libraries. So I did it. But this library creates somes *_Exception class who extend from Exception.
My external library file ends with:
class CloudKey_Exception extends Exception {}
class CloudKey_RPCException extends CloudKey_Exception {public $data = null;}
class CloudKey_ProcessorException extends CloudKey_RPCException {}
class CloudKey_TransportException extends CloudKey_RPCException {}
class CloudKey_SerializerException extends CloudKey_RPCException {}
class CloudKey_AuthenticationErrorException extends CloudKey_RPCException {}
class CloudKey_RateLimitExceededException extends CloudKey_AuthenticationErrorException {}
class CloudKey_InvalidRequestException extends CloudKey_RPCException {}
class CloudKey_InvalidObjectException extends CloudKey_InvalidRequestException {}
class CloudKey_InvalidMethodException extends CloudKey_InvalidRequestException {}
class CloudKey_InvalidParamException extends CloudKey_InvalidRequestException {}
class CloudKey_ApplicationException extends CloudKey_RPCException {}
class CloudKey_NotFoundException extends CloudKey_ApplicationException {}
class CloudKey_ExistsException extends CloudKey_ApplicationException {}
class CloudKey_LimitExceededException extends CloudKey_ApplicationException {}
And when I try to instance my object in controller, Symfony returns this:
Fatal error: Class 'CD\DMBundle\Entity\Exception' not found in /var/www/carpediese/src/CD/DMBundle/Entity/CloudKey.php on line 513
I think Exception class is native PHP5+ class. How can I tell it to Symfony?
Remember to properly set the use statements in files which use the Exception class.
EDIT:
When you refer to any class in PHP 5.3+ just below the namespace declaration you need to add which namespaces you are using for the referenced class (or use the whole namespace when referencing the class). So, if the Exception class you are using belongs to say someLibrary\ClouKey\Exceptions\ namespace you should either have
use someLibrary\CloudKey\Exceptions\Exception;
at the beginning of the file, just below namespace, or use the whole namespace when defining your new class:
class CloudKey_Exception extends someLibrary\CloudKey\Exceptions\Exception {}
EDIT 2:
In the class you are using the Exception is indeed the native PHP class so \Exception should be used. The error you get is generated by this part of the CloudKey class:
public function __get($name)
{
if (!isset($this->objects[$name]))
{
$class = 'CloudKey_' . ucfirst($name);
if (!class_exists($class))
{
$class = 'CloudKey_Api';
}
$this->objects[$name] = new $class($this->user_id, $this->api_key, $this->base_url, $this->cdn_url, $name, $this->proxy, $this->timeout);
$this->objects[$name]->parent = $this;
}
return $this->objects[$name];
}
According to the documentation (http://php.net/manual/en/language.oop5.basic.php):
If a string containing the name of a class is used with new, a new instance of that class will be created. If the class is in a namespace, its fully qualified name must be used when doing this.
So you have to edit the quoted part of the code to use the whole namespace inside the string for the class name.

is it a php bug? (about extends)

class A extends B {}
class B extends C{}
class C {}
result
PHP Fatal error: class 'B' not found ...
if the order is like this
class A extends B {}
class C {}
class B extends C{}
everything is ok.
PS: if I remove class C {}
class A extends B {}
class B extends C{}
php tells me class 'B' is not found, why?
php version 5.3.4
The PHP manual clearly mentions:
Classes must be defined before they
are used! If you want the class
Named_Cart to extend the class Cart,
you will have to define the class Cart
first. If you want to create another
class called Yellow_named_cart based
on the class Named_Cart you have to
define Named_Cart first. To make it
short: the order in which the classes
are defined is important.
clearly a parser bug
this works
class A extends B {}
class B {}
this doesn't
class C extends D {}
class D extends E {}
class E {}
consider reporting on bugs.php.net
Class order matters in PHP definitions.
Does the order of class definition matter in PHP?
This is why you don't have visibility of the class defined after the one you are defining (in this case class A cant see class B because it is defined after).
Because php is interpreted rather than compiled the order of declaration must be valid. In this example class B doesn't exist for A to extend.
Obivously class B is not defined in the moment you trying to extend it, because it occurs after extends B. Its not a bug, its the way the world works: You can only use, what exists ;)

Categories