I'm trying to use PHPMailer through composer.
I'm using namespace and PSR-4 autoloading for my app
My file organisation is like this
-bin
-controllers
- Controller.php (namespace bin\controllers)
-vendor
-phpmailer
-phpmailer
-src
PHPMailer.php (namespace HPMailer\PHPMailer)
In composer.json, I wrote this
"autoload": {
"psr-4": {"bin\\vendor\\phpmailer\\": "bin/vendor/phpmailer/phpmailer/src/PHPMailer.php"}
}
But when I use
<?php
namespace bin\controllers;
use bin\vendor\phpmailer\PHPMailer;
abstract class Controller {
public function __construct()
{
$mail = new PHPMailer();
}
}
I got a fatal error :
require_once(): Failed opening required '/Users/thomas/Library/Mobile
Documents/com~apple~CloudDocs/saveProject/bin/../bin/vendor/phpmailer/PHPMailer.php'
How I could configure the namespace to use the class correctly?
Thanks a lot in advance.
You're mixing up paths and namespaces; for the most part they are independent, but PSR-4 and friends help to map one to the other.
PHPMailer only supports namespaces as of version 6.0, which is not yet released, though you can of course use a pre-release version.
use bin\vendor\phpmailer\PHPMailer;
Should be:
use PHPMailer\PHPMailer\PHPMailer;
The use keyword is used to import an entity from another namespace into the current one - note that this is conceptually different from including a file with include / require.
It looks like you're mixing up namespaces in your own app too - typically you'd use a namespace that's based on a <vendorname>\<projectname> pattern, so your example controller might be :
namespace MyCompany\MyProject;
class MyMailController...
Or you could make use of multiple namespaces within your own project like this:
namespace MyCompany\MyProject\Controllers;
class Mail...
which would define the MyCompany\MyProject\Controllers\Mail class.
Related
I am trying to use Azure storage for php, the setup steps are to include the namespace, include composer autoload and then use the azure classes, so I have the following. However further down I use the class Microgrid and it's not found because of the namespace, it is in a different directory. How can I use other classes that aren't part of that namespace? Also, what's the correct way to specify your namespace path? It's in a different directory relative to the page this is for and the one I am using is not at the root, should I start at the root?
namespace MicrosoftAzure\Storage;
use \MicrosoftAzure\Storage\Common\ServicesBuilder;
use \MicrosoftAzure\Storage\Blob\Models\CreateContainerOptions;
use \MicrosoftAzure\Storage\Blob\Models\PublicAccessType;
use \MicrosoftAzure\Storage\Common\ServiceException;
require_once '/var/www/html/vendor/autoload.php';
$action = MicroGrid::GetParameter('action');
ClassNames are considered relative to the current namespace unless they start with a \
This means that inside the MicrosoftAzure\Storage namespace you can use the relative namespace for class.
If you want to call a class from a different namespace you should call fully-qualified name for it like
$action = \MicrosoftAzure\WhereEver\MicroGrid::GetParameter('action');
or use the name space or unique class with fully-qualified name
use \MicrosoftAzure\WhereEver;
or
use \MicrosoftAzure\WhereEver\MicroGrid;
then:
$action = MicroGrid::GetParameter('action');
Edited to make it clear
namespaces allow us to avoid naming collisions and to alias long
names caused by avoiding naming collisions.
it depends to your autoloader for a simple example I create a new project and make this autoloader in the index.php located at root directory
function __autoload($className){
//if it's a full name with windows style slashes correct the path
$file_name = str_replace('\\', '/', $className);
require_once("vender/src/".$file_name.".php");
}
when I call $date = new \App\Utility\Date(); autoloader will require this file:
verdor/src/App/Utility/Date.php
and in Date.php I used this name space namespace App\Utility;
PHP does not provides a class autoloader out of the box.
There are many autoloaders for PHP, and the most common autoloader standard is the PSR-4, used by many frameworks and applications.
If you are not using an autoloader, you should require every class file (and recursive dependencies) before using it.
Azure uses Composer Autoloader and PSR-4.
You should use Composer Autoloader on your project, then import your class from the right namespace (you are not importing it on your example code)
A namespace basically groups your classes together. You can use something outside your namespace by explicitly using it e.g.
namespace App;
use Illuminate\Database\Eloquent\Model;
In this case I'm 'grouping' this and other classes in a namespace called 'App' but I want to use 'Model' provided by Eloquent (the Eloquent class having a namespace of 'Illuminate\Database\Eloquent') in this class.
If 'Microgrid' is not part of your current namespace, you'll need to explicitly add its namespace in your 'use' statements.
I was just going through the laravel documentation HERE and came across the following peice of code ::
<?php
namespace App\Providers;
use Riak\Connection;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* #return void
*/
public function register()
{
$this->app->singleton('Riak\Contracts\Connection', function ($app) {
return new Connection(config('riak'));
});
}
}
I am new to use in php , just learnt how it functions a few days ago , now does use , when used with a framework like laravel, where one class can be in a directory totally different from another , need to specify the directory structure too ?
I.E. can directory structure impact the way use is used ?
The use statement in PHP (when used outside of a class) is used to import a class from another namespace. Namespaces and folder structure do not necessarily correspond, but it is generally pretty close.
The autoloader used by Laravel, and most other modern PHP applications is part of the Composer package manager. Composer in turn supports multiple namespace standards, most notably PSR-0 and its successor, PSR-4.
In a composer.json file, you'll generally specify a namespace to autoload, and a base directory like so:
{
"autoload": {
"psr-4": {
"My\\Namespace\\": "src"
}
}
}
Any classes in the src/ directory should be in the My\Namespace directory. Classes in src/Model should have the namespace My\Namespace\Model and so on.
What a lot of PHP libraries use nowadays is called an autoloader which may mirror the directory structure, but does not necessarily have to.
I have a PSR-4 specification in my composer.json file as below
"autoload" : {
"psr-4" : {
"MyMVC\\" : "app/"
}
},
Above is my directory structure. In my Core/Config.php file i have class Config that is under namespace MyMVC\Core. (Just taking Config class as example in question, this is same for all classes).
Now in my Config/config.php file i am using below code
<?php
use MyMVC\Core;
Config::$config['base_url'] = 'http://localhost/mymvc';
But this gives me error of Class Config Not Found. The problem can be fixed if i use MyMVC\Core\Config;. But it should work without using Config explicitly. Since there can be files added by the framework user which are supposed to be autoloaded.
Thanks
The use primitive imports or aliases a namespace or class. As the manual states:
PHP supports three kinds of aliasing or importing: aliasing a class name, aliasing an interface name, and aliasing a namespace name. PHP 5.6+ also allows aliasing or importing function and constant names.
Your use statement is "aliasing a namespace". So
use MyMVC\Core;
Is the same as:
use MyMVC\Core as Core;
Thus in your code:
Config::$config['base_url'] = 'http://localhost/mymvc';
Should be:
Core\Config::$config['base_url'] = 'http://localhost/mymvc';
a quick (maybe stupid) question.
I'm using a namespace for my controllers, like so:
namespace Members;
use DB;
use Input;
use PerformanceReport;
use Redirect;
class AdminController extends MembersController {
And as expected, I have to provide use statements for the Laravel classes I wish to use.
From what I've understood, the composer autoloader prevents this from being necessary if used correctly.
So my question being, is it possible to configure the autoloader to suit my needs, and if so, how would I go by doing this?
Your question is connected with the way PHP namespaces work, not with composer's autoloader.
If your class is in namespace Controllers; and you'd write Redirect::to('/') php would assume that the class you're referring to is in the current declared namespace (in that case Controllers/Redirect). You can either write \Redirect::to('/') or put a use Redirect statement on top like you did.
Composer's autoload just maps namespaces to their file directory (see vendor/composer/autoload_classmap.php for how it maps it).
If you want to dive more into composer's autoloading, i'd recommend read up on PSR-0 and PSR-4.
When using the pseudo namespacing pattern of PEAR and Zend, it is common to come across class heirarchies that look like this:
Zend/
Db.php
Db/
Expr.php
Where DB.php contains a class named Zend_Db and Expr.php contains a class named Zend_Db_Expr. However, when you try to convert the old 5.2 psuedo namespacing into PHP 5.3 namespacing you are presented with a case where a namespace and a class share a name. Since the use operator can import either a namespace or a classname this leads to ambiguity.
Here's an example of an app I'm working on converting:
App/
Core.php
Core/
Autoloader.php
Here the base directory and namespace are App. In the top level of the name space is a Core class:
namespace App;
class Core { }
In the Core directory are various other core classes, some of which use the main Core. Under the pseudo namespacing pattern, this isn't a problem. But in the real namespacing pattern it creates this situation:
namespace App\Core;
use App\Core as Core; // What is this importing? Namespace or class?
class Autoloader {
public function __construct(Core $core) {}
}
Is this defined? What is actually imported here?
Simply both. It is not real import, just a hint for compiler, that every encounter of this alias in class related operations should be expanded to this declaration. In php namespace is just part of class so just think of it like this
$alias = 'Zend_Db';
$zendDB = new $alias;
$aliasExpr = $alias . '_Expr';
$expr = new $aliasExpr;