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
Related
I'm currently working on a PHP trait thay will help me to reuse code in some class controllers that I have using Laravel framework.
I wanted to make the trait methods as dynamic as I could but when trying to access to a class that my parent class imported, I get a Class not found exception.
My class controller is as follows:
namespace App\Http\Controllers\Admin;
use App\Models\ {
Curso,
Leccion,
Diapositiva,
ImagenDiapositiva
};
use App\Traits\TestTrait;
class DiapositivasController extends Controller{
use TestTrait;
public function addRecord(Request $request){
$request->class_name = 'ImagenDiapositiva';
$this->addImage($request);
}
}
My Trait:
namespace App\Traits;
trait TestTrait{
public function addImage($request){
$class_name = $request->class_name;
$diapositiva = new $class_name;
//extra code
}
}
So my doubt is, do I have to include the model classes I want to use inside my Trait again or am I doing something else wrong?
if you use new with a variable class name, you have to use the fully qualified class name. I'm guessing new $class_name is the root cause of the issue here, since $class_name would have to be something like: 'App\Models\ImagenDiapositiva' or whatever the full namespace is. Just have to change the call $request->class_name = 'ImagenDiapositiva'; to reflect the full name of the class.
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(){
}
}
?>
I read up quite a bit on namespaces in PHP and I'm still confused.
I have a class in a different folder that is under the namespace Entity (Class A).
I have another class in a different folder that is under the same namespace (Class B), and extends class A.
I get an error saying class A could not be found.
My main question is - do I have to include class A when I create a new instance of class B?
This is my code:
(Class A)
namespace Entity;
//Framework/Entity/BaseModel.php
class BaseModel {
//TODO: IMPLEMENT THIS
public function GetList() {
return null;
}
}
(Class B)
namespace Entity;
//Models/Points.php
class Points extends BaseModel{
public $Id = null;
}
(Main File)
require_once(dirname(dirname(__FILE__)) . '/Models/Points.php');
$points = new Points();
Namespaces have nothing to do with actually including files, those are two completely separate mechanisms. So, yes, you will still have to require_once the file that the class is defined in before you can use it.
Having said that, especially with namespaces, autoloaders are typically used so you don't have to write a ton of require code. If you organise your class files in folders exactly as their namespaces are, it's very easy to autoload their files. See http://php.net/manual/en/language.oop5.autoload.php and https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
Parent class definition must be know on definition of child class.
Even before you create instance of child class.
How otherwise PHP would know what to put inside class you create?
require_once('BaseModel.php')
namespace Entity;
//Models/Points.php
class Points extends BaseModel{
public $Id = null;
}
I'm hoping somebody out there can help me. I am using laravel 4 and I'm writing my first unit tests for a while but am running into trouble. I'm trying to extend the TestCase class but I'm getting the following error:
PHP Fatal error: Class registrationTest contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Illuminate\Foundation\Testing\TestCase::createApplication) in /home/john/www/projects/MyPainChart.com/app/tests/registrationTest.php on line 4
Now if I have this right then the error is referring to the fact that is a method is abstract then the class it's in must also be abstract. As you can see from below the TestCase class it is abstract. I have searched for this error but have drawn a blank.
Trying to follow this cast on Laracasts https://laracasts.com/lessons/tdd-by-example and although you have to be a subscriber to watch the video the file is underneath it and as you can see I am doing nothing different to Jeffrey Way.
My Test:
<?php
class registrationTests extends \Illuminate\Foundation\Testing\TestCase
{
/**
* Make sure the registration page loads
* #test
*/
public function make_sure_the_registration_page_loads_ok()
{
$this->assertTrue(true);
}
}
The beginning of the TestCase class:
<?php namespace Illuminate\Foundation\Testing;
use Illuminate\View\View;
use Illuminate\Auth\UserInterface;
abstract class TestCase extends \PHPUnit_Framework_TestCase {
By the way - the Laravel testing class is not autoloaded by default and so I have tried both the fully qualified class name and use Illuminate\Foundation\Testing and then just extending TestCase. I know it can see it aswhen I don't fully qualify the name it complains that the class cannot be found. I've also tried:
composer dump-autoload
and
composer update
Any help appreciated
According to your error message: Class registrationTest contains 1 abstract method the Base Class contains an abstract method and when a Child Class extends another class with abstract methods then the child class should implement the abstract methods available in Base class. So, registrationTest is child class and \Illuminate\Foundation\Testing\TestCase is the base class and it contains an abstract method:
An abstract method in \Illuminate\Foundation\Testing\TestCase:
abstract public function createApplication();
So, in your child class/registrationTest you must implement this method:
public function createApplication(){
//...
}
But, actually you don't need to directly extend the \Illuminate\Foundation\Testing\TestCase because in app/tests folder there is a class TestCase/TestCase.php and you can extend this class instead:
// In app/tests folder
class registrationTest extends TestCase {
//...
}
The TestCase.php class looks like this:
class TestCase extends Illuminate\Foundation\Testing\TestCase {
public function createApplication()
{
$unitTesting = true;
$testEnvironment = 'testing';
return require __DIR__.'/../../bootstrap/start.php';
}
}
Notice that, TestCase has implemented that abstract method createApplication so you don't need to extend it in your class. You should use TestCase class as base class to create test cases. So, create your tests in app/tests folder and create classes like:
class registrationTest extends TestCase {
public function testBasicExample()
{
$crawler = $this->client->request('GET', '/');
$this->assertTrue($this->client->getResponse()->isOk());
}
}
Read Class Abstraction.
Firstly go in composer.json and add
"scripts" : {"test" : "vendor/bin/phpunit"
}
Then run composer update
Then
The TestCase.php class in path /test/ should look like
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\Artisan;
abstract class TestCase extends BaseTestCase {
use CreatesApplication;
}
Then your registrationTests class should look like this
<?php
namespace Tests\Feature;
use Tests\TestCase;
class registrationTests extends TestCase {}
Just intake dependancy at the top of your class as follows and you are good to go,
<?php
namespace YOUR_CLASS_PATH;
use Tests\TestCase;
class UserTest extends TestCase{
...//your business logic here
}
I hope this works.
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.