Unable to load vendor classes from other namespace - php

I'm having some hard time wrapping around namespaces in PHP, especially when you code needs to interact with scripts residing in another namespace. I downloaded a Shopify API toolkit and trying to get it working. Everything was fine before I started adding namespaces to my code (which is required or threre is script collisition with other Wordpress plugins on my site). Also, the weird namespace {} bit at the top is because in this same file I want a globally accessible function for making the class a singleton.
Looking forward to learning more about how this works.
#### FILE BEING CALLED
namespace {
function SomeFunctionToBeAccessedGlobally() {
return 'Hello';
}
}
namespace MySpecialApp {
class ShopifyImport {
public function __construct() {
// Do Whatever
$this->doImport();
}
public function doImport() {
require __DIR__ . '/vendor/autoload.php';
$credential = new Shopify\PrivateAppCredential('standard_api_key', 'secret_api_key', 'shared_api_key');
$client = new Shopify\Client($credential, 'shop_url', [ 'metaCacheDir' => './tmp' ]);
}
}
}
#### FILE '/vendor/autoload.php'
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit73503f8de5d68cdd40a9c0dfd8a25b44::getLoader();
I do noice that some of the files which where part of the repository cloned into vendor have namespace Slince\Shopify; declarations. I tried to do a use with that namespace within my original namespace but it also didn't work.
The PHP Error being reported is:
Fatal error: Uncaught Error: Class
'MySpecialApp\Shopify\PrivateAppCredential' not found in
/.../ShopifyImporter.php:139 Stack trace: #0 (Blah Blah Blah)

Your code tries to create a new Shopify\PrivateAppCredential() object in the current namespace. However, this class does not exist in your namespace since it is part of the "vendor" namespace.
You can "reset" (read fallback) to the global namespace for your object creations by adding a \ in front of them, as described in the documentation:
$credential = new \Shopify\PrivateAppCredential('standard_api_key', 'secret_api_key', 'shared_api_key');
You can check the difference here without \ and with \.

Related

Namespace with extends or interface causes Fatal Error without autoloader

Why doesn't this work?
web/index.php (Not web/src/App/App.php)
<?php
namespace App;
// web/index.php
require_once __DIR__ . '/../vendor/autoload.php';
$app = new App();
class App extends \Silex\Application {
public function __construct()
{
parent::__construct();
echo 'Worked!';
}
}
I also tried namespace App {...}, no change. It throws this exception:
Fatal error: Uncaught Error: Class 'App\App' not found in /path/to/web/index2.php:8
Stack trace:
#0 {main}
thrown in /path/to/web/index2.php on line 8
As long as I remove the extends ... and the parent call part, it works. I also noticed interface does the same thing (trying to use Serializable). Is this an issue with the autoloader being confused? Is there a way to do this without putting the App\App class into a file in src\App\App.php?
Note: this is an exercise to build a single-file application with Silex, so "just put it in a file" isn't an answer. I want to know why this doesn't work, which has an answer.
The problem in your code is,
In namespace, You are initiating class object before it being declared and loaded. In your above code you are doing same thing,
1. You are initiating App class object which lies in App namespace
2. You are initiating class object at the moment class when is not yet declared(As it is defined below in your code).
In your above code, not even your loader be called. It will be called if you initiate App\App class object after its declaration. and If your loader does not work fine then afterwards you will possibly get this error.
Fatal Error: Silex\Application class not found
Please checkout some examples and findings.
Example 1 Here loader is expected to be called but not called, because you have registered after initialization of class($app = new App();).
Example 2 Here, calling class will look for autoloading class because here initialization takes place after registration of loader and declaration of class, which is probably answers your question.
Change your code with this to get it fix:
<?php
namespace App;
require_once __DIR__ . '/../vendor/autoload.php';
class App extends \Silex\Application {
public function __construct()
{
parent::__construct();
echo 'Worked!';
}
}
$app = new App();

Codeception/AspectMock Parent class not found by locator

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!

Class 'app\routing' not found

I'm currently building an application that will require a few different name spaces, however most of the application I want to put under the app namespace.
In my index.php file I declared to use the app namespace, however PHP still insists my class cannot be found like so...
<?php
define('PATH',strtok ( $_SERVER['REQUEST_URI'] , '?' ));
define("ROOT",$_SERVER['DOCUMENT_ROOT'].'/',true);
require 'vendor/autoload.php';
require 'app/class_loader.php';
use Carbon\Carbon;
use app\routing;
$routing = new routing;
$routing->router();
and inside my routing class I declare it as part of the app namespace like this
<?php
namespace app;
class routing
{
However I keep getting Fatal error: Class 'app\routing' not found in /var/www/my_app/index.php on line 15
This is my autoload file
<?php
function autoload_class_multiple_directory($class_name)
{
# List all the class directories in the array.
$array_paths = array(
'app/controllers',
'app/models',
'app/services',
);
foreach($array_paths as $path)
{
$file = $path.'/'.$class_name.'.php';
if(is_file($file))
{
include $file;
}
}
}
spl_autoload_register('autoload_class_multiple_directory');
I thought this is how namespaces worked? I want to ensure I make my application as easy to follow and code in from the get-go, could somebody please help point me in the right direction?
cheers!

PHP Symfony- How to inherit multiple classes from one php file

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.

PHP does not find Phpstream class (using namespaces and php 5.4.9-4ubuntu2.3)

I installed the pear2 HTTP library using composer, unfortunately I get an error when the library is used (by doctrine, but that should not matter)
h#dev0 ~/Repositories/pfo $ vendor/bin/doctrine-module migrations:migrate
# A few statements before the error I included a statement to get the include path: echo ini_get('include_path');
/home/h/Repositories/pfo/vendor/pear-pear2.php.net/PEAR2_Text_Markdown:/home/h/Repositories/pfo/vendor/pear-pear2.php.net/PEAR2_HTTP_Request:.:/usr/share/php:/usr/share/pear
# Afterwards I get this error:
PHP Fatal error: Class 'pear2\HTTP\Request\Adapter\Phpstream' not found in /home/h/Repositories/pfo/vendor/pear-pear2.php.net/PEAR2_HTTP_Request/pear2/HTTP/Request.php on line 98
# And the Phpstream.php does exist, it begins like this:
namespace pear2\HTTP\Request\Adapter;
use pear2\HTTP\Request;
class PhpStream extends Request\Adapter { ... }
# and is located here:
h#dev0 ~/Repositories/pfo $ ls /home/h/Repositories/pfo/vendor/pear-pear2.php.net/PEAR2_HTTP_Request/pear2/HTTP/Request/Adapter/
Curl.php Filesystem.php Http.php Phpsocket.php Phpstream.php
# The Request.php class looks like this, notice that this file is in a folder together with the Request folder for the 'Request\Adapter\Phpstream' class:
namespace pear2\HTTP;
class Request {
....
public function __construct($url = null, $instance = null) {
echo ini_get('include_path');
...
$this->adapter = new Request\Adapter\Phpstream;
...
}
}
These classes are pear2 libraries and hence I strongly wish not to change them. Is there anything I am missing? Why can't php find the class Phpstream? Does the fact that there is a 'Request' folder and 'Request.php' file make things difficult? The doctrine class loader uses the zend framework class loader, but I am not sure what the impact of that is.

Categories