I am using Symfony 2.4
I have a PHP file OAuth.php which has multiple classes inside that.
Code of OAuth.php is as below
<?php
namespace RT\AuthBundle\DependencyInjection\Vzaar;
use Exception;
class OAuthException extends Exception {
// pass
}
class OAuthConsumer {
//some code
}
class OAuthToken {
//some code
}
?>
I am inheriting above file in Vzaar.php file which is with in same namespace and it's code is as below
<?php
namespace RT\AuthBundle\DependencyInjection\Vzaar;
/*require_once 'OAuth.php';
require_once 'HttpRequest.php';
require_once 'AccountType.php';
require_once 'User.php';
require_once 'VideoDetails.php';
require_once 'VideoList.php';
require_once 'UploadSignature.php';*/
use RT\AuthBundle\DependencyInjection\Vzaar\OAuth;
use RT\AuthBundle\DependencyInjection\Vzaar\HttpRequest;
use RT\AuthBundle\DependencyInjection\Vzaar\AccountType;
use RT\AuthBundle\DependencyInjection\Vzaar\User;
use RT\AuthBundle\DependencyInjection\Vzaar\VideoDetails;
use RT\AuthBundle\DependencyInjection\Vzaar\VideoList;
use RT\AuthBundle\DependencyInjection\Vzaar\UploadSignature;
//use RT\AuthBundle\DependencyInjection\Vzaar\OAuth\OAuthConsumer;
Class Profile
{
public static function setAuth($_url, $_method = 'GET')
{
$consumer = new OAuthConsumer('', '');
//some code
}
}
?>
Creating new object of OAuthConsumer class throws error that
Fatal error: Class 'RT\AuthBundle\DependencyInjection\Vzaar\OAuthConsumer' not found in /var/temp/rt-web/src/RT/AuthBundle/DependencyInjection/Vzaar/Vzaar.php
1/1 ClassNotFoundException: Attempted to load class "OAuthConsumer" from namespace "RT\AuthBundle\DependencyInjection\Vzaar" in /var/temp/rt-web/src/RT/AuthBundle/DependencyInjection/Vzaar/Vzaar.php line 378. Do you need to "use" it from another namespace?
Because since 2.1 Symfony uses composer, and composer uses PSR-0/PSR-4 to autoloading the classes, you have to follow the namespace convention, so you have to create those classes in separate files and in the right directory structure, what is represented in the namespace.
EDIT
As Cerad mentioned in the comment, you can specify a class map in composer, although what is considered as a best practice with symfony projects, create every class in a separate file.
Related
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 created a class at Controller folder of Cake project like this:
<?php
class Hi
{
function __construct(){ }
public function hi()
{
echo "hi!";
exit;
}
}
Then in a controller, I tried to include it:
<?php
namespace App\Controller;
use App\Controller\AppController;
include_once "Hi.php";
class MyController extends AppController
{
public function sayHi()
{
$a = new Hi();
$a.hi();
}
}
Here is the error I'm having:
Fatal error: Cannot declare class Hi, because the name is already in use in path\api\src\Controller\Hi.php on line 2
What's going on?
MyController.php and Hi.php are in the same folder. I'm using PHP 7.
Including a file won't make the classes in that file part of the current namespace, as namespaces are a per-file functionality.
http://php.net/...namespaces.importing.php#language.namespaces.importing.scope
Your Hi class will be declared in the global namespace, and your new Hi() will cause PHP to look for it in the current namespace, ie it will look for App\Controller\Hi, which doesn't exist, hence the composer autoloader kicks in, and will map this via a PSR-4 namespace prefix match to src/Controller/Hi.php, which will include the file again, and that's when it happens.
http://www.php-fig.org/psr/psr-4/
Long story short, while using new \Hi() would fix this, you better not include class files manually, or declare them in paths where they do not belong. Instead declare your files and classes in a proper autoloading compatible fashion, that is for example with a proper namespace in a path that matches that namespace, like
namespace App\Utils;
class Hi {
// ...
}
in
src/Utils/Hi.php
/Core/Api.php
<?php namespace Core;
class Api
{
//
}
start.php
<?php
include 'vendor/autoload.php'
index.php
<?php
include 'start.php';
use Core\Api as Api;
new Api // it's work
start.php
<?php
include 'vendor/autoload.php'
use Core\Api as Api;
index.php
<?php
include 'start.php';
new Api; // Fatal error: Class 'Api' not found
There are many tool class will be used in many places, how to alias it as once in some file and let other file can use the aliased name directly?
use works inside current namespace (for a whole file in most cases) only.
You could create empty class to inheritance target class.
<?php
class Api extends \Core\Api
{}
on index.php I have below code
require 'Bootstrap.php';
require 'Variables.php';
function __autoload($class){
$class = str_replace('Control\\', '', $class);
require_once 'class/'.$class.'.php';
}
$bootstratp = new Control\Bootstrap();
on Bootstrap.php
namespace Control;
class Bootstrap{
function __construct(){
Constructor::load_html();
self::same_namespace_different_class();
}
static function same_namespace_different_class(){
Variables::get_values();
}
}
in class/Constructor.php
class Constructor{
static function load_html(){
echo 'html_loaded';
}
static function load_variables(){
echo 'load variables';
}
}
and on Variables.php
namespace Control;
class Variables{
static function get_values(){
Constructor::load_variables();
}
}
Assume, In total I have 4 PHP files including 3 Class files of 2 different namespaces. I also have a __autoload function on index.php that will call classes from 'class' folder but my 'Control' namespace files are in root folder.
When I echo the class name in __autoload i get the all the class names starting with 'Control\' even when I am calling a class from global namespace.
I am getting below error
Warning: require_once(class/Variables.php): failed to open stream: No such file or directory in _____________ on line 10
what is wrong with my code??
When I echo the class name in __autoload i get the all the class names starting with 'Control\' even when I am calling a class from global namespace.
This is because in Bootstrap.php all the code is in Control namespace (namespace Control). So when you use:
Variables::get_values();
you call
\Control\Variables::get_values();
if you want to use Variables from global namespace you should use here:
\Variables::get_values();
Of course, the same happens for in Variables.php file:
Constructor::load_variables();
As Constructor is defined in global namespace (in class/Constructor.php there is no namespace used), you should access it here using:
\Constructor::load_variables();
If it's still unclear you could also look at this question about namespaces in PHP.
You should also notice that using __autoload is not recommended. You should use spl_autoload_register() now. Documentation about autoloading
I have been searching websites to try and get a handle on using PHP namespaces, but they all seem quite vague but what they're trying to do is easy to understand!
My question is: I have a file called people.php and in it is defined class called people. If I create another file called managers.php in the same folder can I define a class again called people which extends the original people class but in the namespace of managers, if so do I have to 'include' the original people.php and if so do I put the include after the writing: namespace managers?
Namespaces are a way to group your related classes in packages. What you describe could best be put under a single namespace like
<?php // people.php
namespace com\example\johnslibrary\people;
abstract class People {
}
and then
<?php // manager.php
namespace com\example\johnslibrary\people;
require_once 'path/to/People.php'; // can better use autoloading though
class Manager extends People {
}
because a Manager is a subclass of People, so there is not much of a reason to put them into their own namespace. They are specialized People.
If you want to Managers to be in their own namespace, you can do so, but have to use the fully qualified name when using the extends keyword, e.g.
<?php // manager.php
namespace com\example\johnslibrary\managers;
require_once 'path/to/People.php';
class Manager extends \com\example\johnslibrary\people\People {
}
or import the People class first
<?php // manager.php
namespace com\example\johnslibrary\managers;
use com\example\johnslibrary\People as People;
require_once 'path/to/People.php';
class Manager extends People {
}
See the PHP Manual on Namespaces for extensive documentation.
// people.php
<?php
namespace People;
class People {}
// managers.php
<?php
namespace Managers;
require_once __DIR__.'/people.php';
class People extends \People\People {}
I have old PHP Class and i need to use it in new PHP file as for example:index.php has to use iClass.php. But before using the OLD iClass.php i have to modify it as below, so that i can use it in index.php.
iClass.php:
namespace ic;
class iClass {
public static function callMeFromClass() {
echo 'OK - you have called me!';
exit;
}
}
index.php
namespace inex;
require_once 'iClass.php';
use ic\iClass;
iClass::callMeFromClass();