I am trying to add the following library (link) to my Symfony project using composer.
I have run
composer require jaggedsoft/php-binance-api
without a problem but I am getting the following error when loading the page.
Attempted to load class "API" from namespace "App\Controller\Binance".
Did you forget a "use" statement for another namespace?
public function index(){
require '../vendor/autoload.php';
$api = new Binance\API("<api key>","<secret>");
}
Now i am guessing that I need to add a use statement but I am a bit stuck on what it is that I need to add.
To reiterate what I suggested in the comments (options 1 and 3 below):
The namespace of your file - although not explicitly written in your post - is:
App\Controller
without any use statement, the new Binance\API(...) is interpreted as:
App\Controller\Binance\API
which is the concatenation of App\Controller (your namespace) and Binance\API (the classname used).
which of course is not what you want to use, since this is something you tried to include from the binance package. This also explains the error message
Attempted to load class API from namespace App\Controller\Binance. Did you forget a use statement for another namespace?
which is exactly what went wrong. PHP tried to load App\Controller\Binance\API which is class API from namespace App\Controller\Binance.
Now there are A few different ways to fix this:
add use Binance; in the header of your file, then you can use new Binance\API(...)
add use Binance\API; in the header of your file, then you can use new API(...)
don't add a use statement, then you can use new \Binance\APi(...)
add use Binance as Something; in the header of your file, then you can use new Something\API(...); (aliasing the parent namespace Binance as Something may resolve name collisions)
add use Binance\API as BinanceApi; in the header of your file, then you can use new BinanceApi(...);
You decided to use option 1. Which is preferable, if the class (API in this case) isn't very expressive or unique on its own - so is option 5. However, if you use more classes from the Binance namespace, option 1 is preferable.
Option 3 will always work (and might seem preferable if any of the other options seem overkill for some reason) - you can actually get by without any use statement at all, but it can get frustrating to read and write.
Overall, all options are viable and it comes to taste which one to use. Mixing those options may lead to confusion. Inside Symfony I've mostly seen option 2 with the occasional alias (use ... as ...;), especially when using DoctrineORM annotations or when extending some Class which has the same Class name but in a different namespace:
namespace [package1];
use [package2]\[ClassName] as Base[ClassName];
class [ClassName] extends Base[ClassName] { ... }
I hope this explanation helps. The php docs for namespaces are actually helpful, when you understand the core concept of namespaces.
Related
I need to refactor a PHP project where the vendor has undergone a re-brand. The project currently uses the namespace OldCompany, and I need to change this to NewCompany, however I've realized I need to keep the old namespace for backwards compatibility, in the cases where existing users are using try {} catch (/OldCompany/Exception $e) {}... If I simply change the namespace to NewCompany, I will break their integration if they upgrade SDK versions straight up. After reading the PHP Namespace docs, I tried the method outlined in Example #3, and modified all of my files like this:
<?
namespace NewCompany{ /* no namespace-specific code needed */ };
namespace OldCompany{ /* no namespace-specific code needed */ };
namespace {
/* global namespace code. code that applies to both namespaces? */
require_once('file1.php');
require_once('file2.php');
/* classes and functions within the global namespace */
}
The above throws a PHP Fatal Exception and can't find the NewCompany namespace.
I definitely do not want to duplicate code as per Example #2 of the docs, since there isn't namespace-specific code.
What is the best way to preserve the existing namespace of OldCompany for existing users while refactoring a re-brand to `NewCompany' for new users? Should I be looking for a different solution to this problem?
Thanks in advance :)
namespace NewCompany{ /* no namespace-specific code needed */ };
namespace OldCompany{ /* no namespace-specific code needed */ };
This is setting namespaces. But surely your issue is old vendor namespace has changed to a new one? This means you need to import (use) the new namespace instead of the old one?
Maybe I've misunderstood you, but are you confused about the difference between setting and importing namespaces? If the vendor has changed to a new namespace then you need to import the new one, rather than the old one. But this has nothing to do with setting namespaces.
I definitely do not want to duplicate code as per Example #2 of the
docs, since there isn't namespace-specific code.
If there's no namespace specific code then what problem are you trying to resolve?
I need to keep the old namespace for backwards
compatibility, in the cases where existing users are using
try {} catch (/OldCompany/Exception $e) {}.
Surely whatever namespace they have in their end won't affect your side of things? So you could update all your code's namespaces and not worry about what they use? They just call your endpoint or whatever as normal?
Perhaps be more specific about that if it's a real issue somehow.
It sounds to me like you just need to update your import statements for the vendor's new namespace.
Something else to consider is refactor how you manage vendors.
I presume you are not using a pre-made framework, such as Symfony (they have predetermined ways of managing vendors and things).
The fact you are considering refactoring throughout your code rather than a single config file (or whatever) makes me think your code has a design flaw. As it seems you are changing code (namespace) within your class files based on a 3rd party company (vendor) changing their name. And where possible your code should be entirely abstract from such changes to this degree.
I suggest considering abstracting things out into centralised places whenever it makes sense. This allows the one centralised thing to be altered and changes just automatically ripple down to all your code without any need for a huge refactor.
You could make your own generic names for your vendors so whatever they call themselves doesn't matter in your code.
E.g. vendor FunkyJoesEmailer in your app will just be Emailer. Then whichever emailer library you decide to use now and in the future will be in the same Emailer DIR and namespaces won't change, always be Whatever\Emailer.
Then in some file high up the load chain you'd have some wrapper class (or service or container like thing) which would load FunkyJoesEmailer in whatever namespace that is in via your generic name, such as $this->Emailer. So in your code you'd call on $this->Emailer which would return an instance of whatever emailer (vendor) you are using.
If you ever needed to do a namespace change or even entirely swap out the Emailer vendor you use, the change is in one place and would ripple down in your code because it's still $this->Emailer.
While this approach doesn't resolve your having to change everything now, it does mean you only ever have to change it this once. Then in the future can just replace vendors or let their renaming happen within their code and your path (namespace) to it remains the same.
Inside my Controller I want a function to use mpdf e.g.
public function actionPdf(){
include("MPDF57/mpdf.php");
$mpdf=new mPDF('c');
$mpdf->SetDisplayMode('fullpage');
$mpdf->WriteHTML("<h1>Hello World!</h1>");
$mpdf->Output('filename.pdf', 'F');
}
}
This does not work, and throws an error:
Class 'app\controllers\mPDF' not found
What should I do If I want to autoload the class
(a). Just for this Controller Action
(b). To make it usable everywhere just by using the use statement.
I know it has to do something with namespaces but don't know how do I define a namespace, and where do I place this MPDF57 folder and then make it accessible.
I also tried this :
$name = "MPDF57/mpdf.php";
spl_autoload_register(function ($name) {
var_dump($name);
});
But this didn't work either. throws the same error when I call my controller Action.
Here is the namespace declaration and use statements inside :
namespace app\controllers;
use Yii;
use app\models\Regs;
use app\models\Voters;
use app\models\RegsSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use \yii\web\Response;
use yii\helpers\Html;
use kartik\mpdf\Pdf;
Yii has already had autoloader, you do need nothing to load your class.
Just create your class with correct namespace and it will be loaded where are you using it only.
Namspace should represent real path to PHP file. PHP file name and class name should be same.
You should simply use mpdf/mpdf package :
Install it using composer :
composer require "mpdf/mpdf" ">=6.0.0"
Use it like this :
$mpdf = new \mPDF();
Or you can use a yii2 extension like this one : https://github.com/kartik-v/yii2-mpdf
I've faced such problems in one of my previous projects. I'm not good at PHP or Yii2 - so follow my guide on your own risk :)
When you you add use path\to\ExternalLibrary that means the interface is ready to use inside current class (e.g. CurrentController.php).
That means your application knows how to bring your path to it's stage.
E.g. use common\models\Post lets you directly to use Post class, as $posts = new Post;
So if your library contains only one file, just put is some "canonic" path. To common\models\ for example. So you can use it like any other model interface.
But for sake of your project put it on vendor folder. Then install a random library with composer. And observe which files are modified (1-3 generally). Also try to understand the modification logic. When you get sure that you've grasped everything, copy and paste these parts and change the paths, names, etc. for your library.
The best way, I think, is to make your library PSR-4 compatible and ship it as a PHP package. Thus, others can also benefit from your work.
There are lots of guides about making php packages.
http://sitepoint.com/starting-new-php-package-right-way/
https://knpuniversity.com/screencast/question-answer-day/create-composer-package
http://jessesnet.com/development-notes/2015/create-php-composer-package/
http://culttt.com/2014/03/12/build-php-package/
If you are planning to be a good PHP developer, I recommend to look up Josh Lockhart's "Modern PHP: New Features and Good Practices" book ( free pdfs are available :) ). That will help you to understand the fundamentals of OO PHP including namespaces, interfaces etc. So, you will be able to handle such problems in modern way.
From http://phphttpclient.com I followed "Install option 1" and the first "quick snippet".
I end up with the following, with Request undefined.
Additionally, and perhaps relatedly, I am confused by the fact that one of the code samples says "$response = Request::get" and another says "$response = \Httpful\Request::get". Is the latter valid PHP?
I have PHP 5.6.7.
What am I doing wrong?
Yes, \Httpful\Request::get() is valid PHP. It tells PHP that you're looking for the class Request in the namespace Httpful. More on namespaces: http://php.net/manual/en/language.namespaces.php
The reason you can call \Httpful\Request::get(), but can't call Request::get() is namespace related. In your index.php, you're not defining a namespace. Therefor, PHP just looks for a class Request in the global space (when calling Request::get()). PHP does not check if there's a Request class in another namespace.
You can use (import) a class, that will prevent you from having to type the entire namespace everytime you want to use the Request class:
<?php
use Httpful\Request;
$request = Request::get()
# you can also rename the class if you have multiple Request classes
use Httpful\Request as Banana;
$request = Banana::get()
More on that subject: http://php.net/manual/en/language.namespaces.importing.php
I just followed the 'quick-hack' install suggested by the author and got the same result. I then used the fully qualified namespace and got it working.
as :
$response = \Httpful\Request::get($uri)->send(); // qualified namespace here
I'll stick to the hack while i kick the tires, then if i adopt the lib, i'll go the composer route (much much better imo).
Best everyone,
There is one thing in Laravel 4 I just can't understand if you create a namespace in my case cms and you want to use for instance View::make or Input::all()
laravel wil tell you it could not be found what is correct since those methods are in the global namespace and not in cms so to get it to work you can refer to it with adding a backslash before the method that will it wil user the global namespace. however i find that confusing isn't there a way to have a use or something that imports all the Input, Hash, Redirect enz.. So you could use it without adding \.
Not sure I completely follow, do you mean: using View::all() without doing \View::all() in a cms Namespaced file?
If so you can import namespaces by using the use keyword and alias them by using the as keyword
e.g.
use MyNameSpace\View; // Imports only
use MyNameSpace\View as MyView; // Imports and Aliases
class {
....
}
For more details please see http://php.net/manual/en/language.namespaces.importing.php
basically, I have the following problem: I want to make use of PHP's new namespace features. Unfortunately, I'm running a PHP version (5.3.2) in which namespace-autoload-support for linux still seems buggy and does not work (PHP should be able to load the class file automatically by its namespace without having to use a custom autoloader, but that doesn't work).
What I want to achieve is to write an autoloader that I can simply remove as soon as the php's namespace features work correctly (there seems to be a speed advantage when not using a custom autoloader) with having to change as less code as possible afterwards.
So I have a call like this:
$filereader = new system\libraries\file\XML();
which gets passed correctly as the string "system\libraries\file\XML" to my autoload-function. I can load the corresponding file "system/libraries/file/XML.class.php". However, the class in there will be named
class XML { ... }
(or something different than "system\libraries\file\XML") and so have a different name than the one by which PHP will try to load it. So is there an easy way to load that class ("XML") which has a different name than the name which I pass to the autoloader function? Can I perhaps do something in the autoloader to achieve that behaviour? (I'm using spl_autoload_register).
I know that even if it worked out I would still not be able to use all features of namespacing, since a (simple) autoloader would not respect the "use namespace" directive and I would still have to use rather long names for loading a class. However, if I understood PHP's namespace-features correctly, I could leave the code as it is when I later switch to using native namespace support instead of my autoloader.
If what I try to do does not make sense at all in your opinion or if I misunderstood namespaces, please tell me (- I have not used PHP's namespace features yet).
I would load the file (which creates the XML class) and then alias the XML class to the properly namespaced system\libraries\file\XML class:
class_alias('XML', 'system\libraries\file\XML');
More generally:
class_alias(basename($class), $class));
Though I'm not quite sure whether class_alias can alias to namespaced classes...