I am new with this namespace thing.
I have 2 classes(separate files) in my base directory, say class1.php and class2.php inside a directory src/.
class1.php
namespace \src\utility\Timer;
class Timer{
public static function somefunction(){
}
}
class2.php
namespace \src\utility\Verification;
use Timer;
class Verification{
Timer::somefunction();
}
When I execute class2.php, i get the Fatal error that
PHP Fatal error: Class 'Timer' not found in path/to/class2.php at
line ***
I read somewhere on SO, that I need to create Autoloaders for this. If so, how do I approach into creating one, and if not, then what else is the issue?
UPDATE
I created an Autoloader which will require all the required files on top of my php script.
So, now the class2.php would end up like this.
namespace \src\utility\Verification;
require '/path/to/class1.php'
use Timer;
//or use src\utility\Timer ... both doesn't work.
class Verification{
Timer::somefunction();
}
This also does not work, and it shows that class not found. But, if I remove all the namespaces, and use's. Everything works fine.
We can solve the namespace problem in two ways
1) We can just use namespace and require
2) We can use Composer and work with the autoloading!
The First Way (Namespace and require) way
Class1.php (Timer Class)
namespace Utility;
class Timer
{
public static function {}
}
Class2.php (Verification Class)
namespace Utility;
require "Class1.php";
//Some interesting points to note down!
//We are not using the keyword "use"
//We need to use the same namespace which is "Utility"
//Therefore, both Class1.php and Class2.php has "namespace Utility"
//Require is usually the file path!
//We do not mention the class name in the require " ";
//What if the Class1.php file is in another folder?
//Ex:"src/utility/Stopwatch/Class1.php"
//Then the require will be "Stopwatch/Class1.php"
//Your namespace would be still "namespace Utility;" for Class1.php
class Verification
{
Timer::somefunction();
}
The Second Way (Using Composer and the autoloading way)
Make composer.json file. According to your example "src/Utility"
We need to create a composer.json file before the src folder. Example: In a folder called myApp you will have composer.json file and a src folder.
{
"autoload": {
"psr-4": {
"Utility\\":"src/utility/"
}
}
}
Now go to that folder open your terminal in the folder location where there is composer.json file. Now type in the terminal!
composer dump-autoload
This will create a vendor folder. Therefore if you have a folder named "MyApp"
you will see vendor folder, src folder and a composer.json file
Timer.php(Timer Class)
namespace Utility;
class Timer
{
public static function somefunction(){}
}
Verification.php (Verification Class)
namespace Utility;
require "../../vendor/autoload.php";
use Utility\Timer;
class Verification
{
Timer::somefunction();
}
This method is more powerful when you have a complex folder structure!!
You are going to need to implement an autoloader, as you have already read about it in SO.
You could check the autoloading standard PSR-4 at http://www.php-fig.org/psr/psr-4/ and you can see a sample implementation of PSR-4 autoloading and an example class implementation to handle multiple namespaces here https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md.
Related
I did brows through that question page but the answers given, I felt, didn't sufficiently answer the question I was struggling with.
I have a little php project. In this project I define two classes both in their own files. The second class extends the first class. In the app.php file I instantiate the second class and call a method.
├── Models/
│ ├── Class1.php
│ └── Class2.php
└── app.php
<?php
// Class1.php
namespace Models\Class1;
/**
* Class1 does things
*/
class Class1 {
public function someMethod() {
// code
}
}
<?php
// Class2.php
namespace Models\Class2;
use \Models\Class1\Class1;
include('./Class1.php');
/**
* Class2 does other things
*/
class Class2 extends Class1 {
public function someMethod() {
// code
}
}
<?php
// app.php
use Models\Class1\Class1;
use Models\Class2\Class2;
require('Models/Class1.php');
require('Models/Class2.php');
$c1 = new Class1();
$c2 = new Class2();
Now I'm not a really experienced php programmer but I thought I had a solid grasp of this class/namespace business and including/requiring files, but apparently I don't.
If I copy the methods I need from Class1 to Class2 and not extend/include/use Class2 everything works fine, but want to extend Class1, so I don't have to repeat myself! Damn it!
This is what I get when running the app.php file.
Warning: include(../Models/Class1.php): failed to open stream: No such file or directory in C:\wamp64\www\project\Models\Class2.php on line 8
Warning: include(): Failed opening '../Models/Class1.php' for inclusion (include_path='.;C:\php\pear') in C:\wamp64\www\project\Models\Class2.php on line 7
I've been reading all I can find online about this stuff, have written and rewritten my code in a dozen different ways but have yet to find a solution. Some help would be greatly appreciated!
Quick Answer
Unless you've specified the full path to the include file, PHP will always try to resolve files according to the location of the entry script. In your case, your entry script seems to be app.php at the root of the application.
So in your Class2.php, instead of include('./Class1.php');, you should write include('Models/Class1.php'); and things should work. But while it fix a short term problem, your code would be really non-portable. Besides, including the same file twice would result in another error (e.g. re-declaring class).
Slightly Smarter Approach
A slightly smarter would be to do this in Class2.php instead.
<?php
// Class2.php
namespace Models\Class2;
use \Models\Class1\Class1;
include_once __DIR__ . '/Class2.php';
/**
* Class2 does other things
*/
class Class2 extends Class1 {
public function someMethod() {
// code
}
}
The variable __DIR__ will always be resolved to the directory of the script file, not the entry script.
But again, it is clumsy and error prone to do file includes by hand.
An Even Smarter Approach: Autoload
PHP supports file autoloading when a class is declare. That is to have a piece of code to do the file include when a class is called. If you want to have fun, you're welcome to write your own autoloader function and register to spl_autoload_register. With a combination of the __DIR__ technique we talked about, you can easily resolve the autoloading path from namespace.
A quick and ugly autoloading app.php would probably look like this:
<?php
// app.php
use Models\Class1\Class1;
use Models\Class2\Class2;
spl_autoload_register(function ($class_name) {
$realClassName = basename(str_replace('\\', DIRECTORY_SEPARATOR, $class_name));
include_once __DIR__ . DIRECTORY_SEPARATOR . 'Models' . DIRECTORY_SEPARATOR . $realClassName . '.php';
});
$c1 = new Class1();
$c2 = new Class2();
The Smart Approach: Composer Autoload
If you're learning OOP PHP today, I'd highly recommend you to learn Composer and PSR-4. PSR-4 defines how you should structure a PHP application for class autoloading. Composer implements a PSR-4 autoloader by default.
First you should comply with the namespace standard. The least change to do is to loose the extra "Class1" and "Class2" in your namespace:
<?php
// Class1.php
namespace Models;
/**
* Class1 does things
*/
class Class1 {
public function someMethod() {
// code
}
}
<?php
// Class2.php
namespace Models;
use \Models\Class1;
/**
* Class2 does other things
*/
class Class2 extends Class1 {
public function someMethod() {
// code
}
}
With a nicely structured application folder, namespace structure and a correctly written autoload.psr-4 section in composer.json, composer will help you to generate a class autoloader. Your composer.json would probably look like this:
{
"autoload": {
"psr-4": {
"Model\\": "Model/"
}
}
}
You may now run composer dump-autoload to create the autoloader. Then you can simply add this to your entry script app.php. When things are ready, you may simply add use and new statement anywhere in the application.:
<?php
// app.php
use Models\Class1;
use Models\Class2;
require_once './vendor/autoload.php';
$c1 = new Class1();
$c2 = new Class2();
All includes are handled by the autoloader. Hands free.
Remove the line
include('./Class1.php');
I am new with this namespace thing.
I have 2 classes(separate files) in my base directory, say class1.php and class2.php inside a directory src/.
class1.php
namespace \src\utility\Timer;
class Timer{
public static function somefunction(){
}
}
class2.php
namespace \src\utility\Verification;
use Timer;
class Verification{
Timer::somefunction();
}
When I execute class2.php, i get the Fatal error that
PHP Fatal error: Class 'Timer' not found in path/to/class2.php at
line ***
I read somewhere on SO, that I need to create Autoloaders for this. If so, how do I approach into creating one, and if not, then what else is the issue?
UPDATE
I created an Autoloader which will require all the required files on top of my php script.
So, now the class2.php would end up like this.
namespace \src\utility\Verification;
require '/path/to/class1.php'
use Timer;
//or use src\utility\Timer ... both doesn't work.
class Verification{
Timer::somefunction();
}
This also does not work, and it shows that class not found. But, if I remove all the namespaces, and use's. Everything works fine.
We can solve the namespace problem in two ways
1) We can just use namespace and require
2) We can use Composer and work with the autoloading!
The First Way (Namespace and require) way
Class1.php (Timer Class)
namespace Utility;
class Timer
{
public static function {}
}
Class2.php (Verification Class)
namespace Utility;
require "Class1.php";
//Some interesting points to note down!
//We are not using the keyword "use"
//We need to use the same namespace which is "Utility"
//Therefore, both Class1.php and Class2.php has "namespace Utility"
//Require is usually the file path!
//We do not mention the class name in the require " ";
//What if the Class1.php file is in another folder?
//Ex:"src/utility/Stopwatch/Class1.php"
//Then the require will be "Stopwatch/Class1.php"
//Your namespace would be still "namespace Utility;" for Class1.php
class Verification
{
Timer::somefunction();
}
The Second Way (Using Composer and the autoloading way)
Make composer.json file. According to your example "src/Utility"
We need to create a composer.json file before the src folder. Example: In a folder called myApp you will have composer.json file and a src folder.
{
"autoload": {
"psr-4": {
"Utility\\":"src/utility/"
}
}
}
Now go to that folder open your terminal in the folder location where there is composer.json file. Now type in the terminal!
composer dump-autoload
This will create a vendor folder. Therefore if you have a folder named "MyApp"
you will see vendor folder, src folder and a composer.json file
Timer.php(Timer Class)
namespace Utility;
class Timer
{
public static function somefunction(){}
}
Verification.php (Verification Class)
namespace Utility;
require "../../vendor/autoload.php";
use Utility\Timer;
class Verification
{
Timer::somefunction();
}
This method is more powerful when you have a complex folder structure!!
You are going to need to implement an autoloader, as you have already read about it in SO.
You could check the autoloading standard PSR-4 at http://www.php-fig.org/psr/psr-4/ and you can see a sample implementation of PSR-4 autoloading and an example class implementation to handle multiple namespaces here https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md.
I just started using CakePHP 3. I'm trying to get up and running but doing the simplest of things is proving to be a headache.
I have a class, MySimpleClass, in src/App/MySimpleClass.php
<?php
namespace MyApp\MyNamespace;
class MySimpleClass {
public function aSimpleFunction() {
return 1;
}
}
And in my controller:
<?php
namespace App\Controller;
use Cake\Controller\Controller;
use MyApp\MyNamespace\MySimpleClass;
class MyFirstController extends Controller {
public function display() {
$mySimpleClass = new MySimpleClass();
echo $mySimpleClass->aSimpleFunction();
}
}
But this always gives me:
Error in: ROOT/src/Controller/TestController.php, line 10 Class 'MyApp\MyNamespace\MySimpleClass' not found
I use bin/cake server to run the HTTP server
I added App::className('MyApp\MyNamespace\MySimpleClass'); to bootstrap.php to see if that'd make a difference but it doesn't.
I've run composer dump-autoload on several occasions.
I tried putting MySimpleClass into global namespace but it still gave me the error.
PHPStorm isn't giving me any syntax or naming errors.
You should place your controllers in:
src/Controller
and use:
namespace App\Controller;
Nevermind, I finally found the solution...
I just had to add src to the classmap in composer.json:
"autoload": {
"classmap": [
"src"
],
...,
}
Edit:
Instead of abusing classmap, I just moved my class files to a directory outside of src
If your class is in the file src/App/MySimpleClass.php, the namespace has to be App\App. The first App refers to the root namespace of every CakePHP 3.x application, the second App refers to the subdirectory within the src directory you put your class file into.
If the namespace of the class should be App\MyNamespace, your classfile has to be located in src/MyNamespace.
Also: according to the error message you quoted, your MyFirstController is in a file called TestController.php. Instead, it should be MyFirstController.php. I recommend giving https://book.cakephp.org/3.0/en/intro/conventions.html#file-and-class-name-conventions a read regarding this topic.
I have a problem with Codeception/AspectMock.
When using custom autoloader and try to create an instance of a class which has parent form the same custom namespace I have this error:
PHP Fatal error: Uncaught InvalidArgumentException: Class [parent
class name] was not found by locator in
vendor/goaop/parser-reflection/src/ReflectionEngine.php:112
I have very simple setup:
<?php
require_once __DIR__ . '/vendor/autoload.php';
$kernel = AspectMock\Kernel::getInstance();
$kernel->init([
'debug' => true,
'includePaths' => [__DIR__. '/lib'],
]);
$kernel->loadFile(__DIR__ . '/autoload.php'); // custom autoloader
$b = new \lib\B();
Class \lib\B:
namespace lib;
class B extends A {}
Class \lib\A:
namespace lib;
class A
{
public function getName()
{
return static::class;
}
}
Class B is loaded via my custom autoloader, but then the locator tries to load parent class A via composer autoloader and returns this error. Is this a bug, or I'm doing something wrong?
The topic starter has already got an answer on GitHub.
In order to use custom autoloader you should re-init ReflectionEngine with composite class locator that will be able to locate your classes or you can use CallableLocator with closure for resolving paths.
Or, even better you could switch your code base to the PSR0/PSR-4
For example:
$kernel->loadFile(__DIR__ . '/autoload.php'); // custom autoloader
\Go\ParserReflection\ReflectionEngine::init(
new class implements \Go\ParserReflection\LocatorInterface {
public function locateClass($className) {
return (new ReflectionClass($className))->getFileName();
}
}
);
$b = new \lib\B(); // here you go
If you can easily do a find and replace on your codebase, maybe you could refactor your code to PSR-4 autoloading standards and do away with the need for a custom autoloader altogether.
This is the spec https://www.php-fig.org/psr/psr-4/. I'll try and explain it as simply as possible.
Imagine changing your lowercase namespace lib to Lib, and setting that namespace to the src/ directory in your composer.json:
"autoload": {
"psr-4": {
"Lib\\": "src/"
}
}
After setting that, run composer dumpautoload. Then all you need to do is search and replace namespace lib;, replacing with namespace Lib;.
An example class located in src/Form.php would have namespace Lib; at the top, followed by class Form.
<?php
namepace Lib;
class Form
{
// code
}
Namespaces use the folder naming convention. All classes directly in src/ have namespace Lib;. If there are subdirectories, the directory name becomes part of the namespace. For example a file in src/Form/Field/Text.php would have namespace Lib\Form\Field; class Text {}.
<?php
namepace Lib\Form\Field;
class Text
{
// code
}
You can see the full convention in the link above, but the general rule is make any folders begin with a capital letter, as with your classname, and the autoloader should be able to find all of your classes.
This is probably the best practice solution for you, and again as I said, only requires a little bit of file renaming and namespace tweaking. Good luck!
I have got a single file in which I need specify classes in multiple namespaces, something like:
<?php
namespace library;
class ClassInLib {
...
}
namespace \; //Switch to root namespace
class ClassInRoot {
...
}
The above code has a syntax error at namespace \;. How can I switch from the library namespace to the root namespace?
Why do I need this: I need to mock a bunch of classes during unit testing and I don't think these very short mock classes justify being in separate files.
namespace
{
class RootClass
{
function whatever();
}
}
namespace Symfony\Component\DependencyInjection
{
interface ContainerAwareInterface
{
function setContainer(ContainerInterface $container = null);
}
}
http://www.php.net/manual/en/language.namespaces.definitionmultiple.php
Good chance you will decide to use separate files anyways.
I struggled with this for a while - I put the class files I wanted to be global namespaced ( e.g. I want to use them as \myClass ) into their own folder and I removed any namespace ... ; declared in the files.
Then in composer.json add in classmap to the directory I'd made:
"autoload": {
"classmap": [
"directoryWith/subDirIfNeeded"
]
...
}
Then don't forget to composer dumpautoload whenever you make a change to composer.json