I'm developing some packages a lot of which are based on code that was in the main app, or from examples that are based on writing the code in an app rather than a package. I keep forgetting to add a Use View; or Use Controller; in the various files and am having to manually check and add these to every single PHP script (that needs them) in the package.
Is there a way of automating this so that I only have to declare them once in a package, or better still get them to pass through to the facades in the main app?
I'm afraid there isn't.
This is because your package code has its own namespace, and so does the Illuminate core.
PHP's use-statements are only on per-file basis.
When your scripts uses classes from another namespace, you have 2 options.
Adding use-statements (to the Facades) to alias the class to the current namespace
Referencing the full namespace of the facade (starting from the global namespace ), either the alias in the global namespace which Laravel automatically creates (\View), or the original full namespace of the facade (\Illuminate\Support\Facades\View)
Example of referencing the full namespace:
<?php
namespace My\Package;
class SomeClass
{
public function doSomething()
{
// reference full namespace
$view = \Illuminate\Support\Facades\View::make('someview');
// or
$view = \View::make
}
}
?>
This might seem as a way to not have to use use-statements, but in my opinion it's worse. So I recommend u to just get used to adding these use-statements.
You should see it as a best practice: these use-statements clearly state the dependencies of your class (or file). It's always better to try and lower the amount of these.
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.
I'm currently reading Modern PHP Book and I'm a little confused since in Chapter 2 the author talks about Namespace and he keeps saying import when he refers to the "use". In fact he states the following...
TIP
You should import code with the use keyword at the top
of each PHP file, immediately after the opening <?php tag or...
The way I understand Namespace is that the use keyword references the namespace of the class but it doesn't import it and you still need to use require or include to import the actual class, correct?
I'm I correct when I say that when using namespace without auto-loading you will need to use require or include to import your classes?
Thanks
If you use autoloader, such as composer, you do not need to import or require PHP files (you only load autoloader file, which actually does all that for you). If you have no autoloader, you have to load files using import or require.
Then, after FILE is loaded, you can use use statements to do actual work with name-spaced items, such as classes, interfaces or traits.
Yes, you're correct. The use keyword in PHP merely aliases a namespace, in that it does what a symlink (on a *nix system) or shortcut (on a Windows system) would.
If you read the manual about PHP namespace basics you'll see that namespaces can be analogous to a filesystem where class/interface/constant/function names can be divided up into folders in order to prevent name-clashes.
If you read the manual section on Namespace Importing you'll see that when we refer to importing in PHP it actually means to create a shortcut of one name to another name (in fact the shortcut analogy above is taken right from the manual)...
This is similar to the ability of unix-based filesystems to create symbolic links to a file or to a directory.
So, while confusing, the use keyword in PHP does not attempt to load (or include) the actual file containing the namespace, but rather just creates an alias for given namespace(s).
This may be very different use of the word import than you may be used to in other languages, where import can mean to load the actual file or package, but in PHP it's important to understand that importing a namespace has nothing to do with autoloading or including files. They are two separate concepts in PHP.
Importing a namespace is so that you can refer to \fully\qualified\namespace\MyClass as simply MyClass inside your namespace rather than having to use the FQN every single time (hence the shortcut analogy).
Autoloading, is for including the actual classes in PHP when they get used in code.
So there's a definite disconnect between the two concepts.
Since you mentioned a Chapter 2 in a book, I'm going to assume that you are still learning PHP, yes?
The use of use is to shorten namespaced classes to their root so that if you have some long namespaced class like
org\shared\axel\web\framework\connection\pipeline\impl\StopExecutionException
that needs to be instantiated with
new org\shared\axel\web\framework\connection\pipeline\impl\StopExecutionException();
You can use use to refer only to the root unnamespaced class
use org\shared\axel\web\framework\connection\pipeline\impl\StopExecutionException;
...
throw new StopExecutionException();
Keep in mind that you still need to have the class's code in your script, so you either include/require that manually by using include or require, or register autoloaders (see spl_autoload_register).
What that does is you define how your namespace maps to your source code's directory structure.
What others here refer to as composer is a package manager that includes an autoloader. At this stage, I personally think it's better to put off learning about this until you have a good grasp of the basics.
If you have an autoloader then use can be used to pull a Trait
Trait file
namespace Blah;
Trait Foo {
protected $somevar;
}
Class file
Class Bar {
use \Blah\Foo; // autoloaded
}
Otherwise, use is used to indicate that you want to either load a given class or alias that class as another
Class Foo {
}
use \Foo as Bar;
Class Something extends Bar {
}
I have one namespace (for example \App\) that contains all my app encapsulated, currently I'm using composer to autoload this namespace using PSR-0 and checking for two different folders, "Main" and "Client". (Giving priority to the client folder, allowing me to override the main app functionality to meet the client's requests by only creating the necessary override files in the client's folder)
Now, I'm thinking that it would be better if the client's override classes extended the original one, because I realized that the main use for this is to edit only some of the class methods, and I want to future proof the "override class" for new methods that could appear in the "main class". And I've been struggling with a way to make this happen, keeping the namespaces.
Example: Sales Controller Class ==> \App\Controller\Sale
If there isn't a "Client/App/Controller/Sale.php" file it uses the default "Main/App/Controller/Sale.php"
But if there is, what I want is that "Client/App/Controller/Sale.php" could be able to extend "Main/App/Controller/Sale.php"
<?php
namespace App\Controller
use \Main\Controller\Sale as OriginalClass //The Sale class in Main Folder
class Sale extend OriginalClass {...}
This way, I could override only some methods in the client's class and if the main class gets updated it would be reflected in the client's app.
The problem is, that since both, the client and main class are in the \App\ namespace, I can't figure out a way to get the "use" statement above to work. The main reason is that any prepended namespace (in the example "\Main + namespace) that I put in it won’t work, because the file's namespace would be different.
Another way I thought it could work is by tinkering with the composer autoload, and check if the namespace starts with "Main" or maybe "Original", then remove that part from the namespace and force to use the "Main" folder. But I couldn't find where this could be implemented.
Another solution I considered was to subdivide the main class functionality in sub classes, that could be overridden using the current autoload scheme, but I don't know if it is wise to have so many classes and files scattered through the system.
Any help or guidance is always welcome.
No Solution, but a workaround
I ended up separating the clients and main classes namespaces. Then, I made a function that recives a class name and checks if the class exists in the client's folder and prepend the "Client\" namespace, or append the "Main\" namespace before initializing.
So
$class = "Path\\To\\My\\Class";
$class = checkClass($class);
// Now class is either "Client\\Path\\To\\My\\Class; or Main\\Path\\To\\My\\Class;
//Uses:
$object = new $class();
$static = $class::StaticMethod();
Also, the "Client" version of the classes extends their "Main" --base-- class.
Eg: Client\MyClass extends Main\MyClass
I'm trying to rewrite an OO PHP site (that loosely follows an MVC structure) so it uses namespaces - and want to follow PSR-0.
In the current site I have a class (called APP) which is full of static methods that I call all over the place to handle things such as getting config data eg; APP::get_config('key').
Obviously with namespacing, I would need to call \TheNameSpace\App::get_config('key'). I use this class frequently, so want to avoid having to prefix the namespace every time I use it. I do call methods in it from within other classes, which would usually be under a sub-namespace - so changing the namespace at the top of the file won't really work.
So, I guess my question is, what is the easiest way to have a 'global' class with methods that I can call anywhere without having to prefix with the namespace each time?
namespace Foo;
use Bar;
Then you do not have to do \Bar\fn
So in your case:
namspace Foo;
use TheNameSpace\App;
App::get_config('blah')
Read the section in the php manual on using/aliasing namespaces.
http://www.php.net/manual/en/language.namespaces.importing.php
You can exclude the namespace by using "use". You can name it whatever you want.
use TheNamespace\App as App //You can name it anything here
App:config('key');
At top of your scripts add
use TheNameSpace\App as MyApp
for example. You can then use it like
app = new MyApp();
in your scripts. Of course you needn't to use an alias here. Just
use TheNameSpace\App
app = new App();
will work, too.
A global class that's implementing this one is bad style and you shouldn't do it like this:
class MyApp extends TheNameSpace\App { }
....
myApp = new MyApp();
I have a file with a class Resp. The path is:
C:\xampp\htdocs\One\Classes\Resp.php
And I have an index.php file in this directory:
C:\xampp\htdocs\Two\Http\index.php
In this index.php file I want to instantiate a class Resp.
$a = new Resp();
I know I can use require or include keywords to include the file with a class:
require("One\Classes\Resp.php"); // I've set the include_path correctly already ";C:\xampp\htdocs". It works.
$a = new Resp();
But I want to import classes without using require or include. I'm trying to understand how use keyword works. I tried theses steps but nothing works:
use One\Classes\Resp;
use xampp\htdocs\One\Classes\Resp;
use htdocs\One\Classes\Resp;
use One\Classes;
use htdocs\One\Classes; /* nothing works */
$a = new Resp();
It says:
Fatal error: Class 'One\Classes\Resp' not found in C:\xampp\htdocs\Two\Http\index.php
How does the keyword use work? Can I use it to import classes?
No, you can not import a class with the use keyword. You have to use include/require statement. Even if you use a PHP auto loader, still autoloader will have to use either include or require internally.
The Purpose of use keyword:
Consider a case where you have two classes with the same name; you'll find it strange, but when you are working with a big MVC structure, it happens. So if you have two classes with the same name, put them in different namespaces. Now consider when your auto loader is loading both classes (does by require), and you are about to use object of class. In this case, the compiler will get confused which class object to load among two. To help the compiler make a decision, you can use the use statement so that it can make a decision which one is going to be used on.
Nowadays major frameworks do use include or require via composer and psr
1) composer
2) PSR-4 autoloader
Going through them may help you further.
You can also use an alias to address an exact class. Suppose you've got two classes with the same name, say Mailer with two different namespaces:
namespace SMTP;
class Mailer{}
and
namespace Mailgun;
class Mailer{}
And if you want to use both Mailer classes at the same time then you can use an alias.
use SMTP\Mailer as SMTPMailer;
use Mailgun\Mailer as MailgunMailer;
Later in your code if you want to access those class objects then you can do the following:
$smtp_mailer = new SMTPMailer;
$mailgun_mailer = new MailgunMailer;
It will reference the original class.
Some may get confused that then of there are not Similar class names then there is no use of use keyword. Well, you can use __autoload($class) function which will be called automatically when use statement gets executed with the class to be used as an argument and this can help you to load the class at run-time on the fly as and when needed.
Refer this answer to know more about class autoloader.
use doesn't include anything. It just imports the specified namespace (or class) to the current scope
If you want the classes to be autoloaded - read about autoloading
Don’t overthink what a Namespace is.
Namespace is basically just a Class prefix (like directory in Operating System) to ensure the Class path uniqueness.
Also just to make things clear, the use statement is not doing anything only aliasing your Namespaces so you can use shortcuts or include Classes with the same name but different Namespace in the same file.
E.g:
// You can do this at the top of your Class
use Symfony\Component\Debug\Debug;
if ($_SERVER['APP_DEBUG']) {
// So you can utilize the Debug class it in an elegant way
Debug::enable();
// Instead of this ugly one
// \Symfony\Component\Debug\Debug::enable();
}
If you want to know how PHP Namespaces and autoloading (the old way as well as the new way with Composer) works, you can read the blog post I just wrote on this topic: https://enterprise-level-php.com/2017/12/25/the-magic-behind-autoloading-php-files-using-composer.html
You'll have to include/require the class anyway, otherwise PHP won't know about the namespace.
You don't necessary have to do it in the same file though. You can do it in a bootstrap file for example. (or use an autoloader, but that's not the topic actually)
The issue is most likely you will need to use an auto loader that will take the name of the class (break by '\' in this case) and map it to a directory structure.
You can check out this article on the autoloading functionality of PHP. There are many implementations of this type of functionality in frameworks already.
I've actually implemented one before. Here's a link.
I agree with Green, Symfony needs namespace, so why not use them ?
This is how an example controller class starts:
namespace Acme\DemoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class WelcomeController extends Controller { ... }
Can I use it to import classes?
You can't do it like that besides the examples above. You can also use the keyword use inside classes to import traits, like this:
trait Stuff {
private $baz = 'baz';
public function bar() {
return $this->baz;
}
}
class Cls {
use Stuff; // import traits like this
}
$foo = new Cls;
echo $foo->bar(); // spits out 'baz'
The use keyword is for aliasing in PHP and it does not import the classes. This really helps
1) When you have classes with same name in different namespaces
2) Avoid using really long class name over and over again.
Using the keyword "use" is for shortening namespace literals. You can use both with aliasing and without it. Without aliasing you must use last part of full namespace.
<?php
use foo\bar\lastPart;
$obj=new lastPart\AnyClass(); //If there's not the line above, a fatal error will be encountered.
?>
Namespace is use to define the path to a specific file containing a class e.g.
namespace album/className;
class className{
//enter class properties and methods here
}
You can then include this specific class into another php file by using the keyword "use" like this:
use album/className;
class album extends classname {
//enter class properties and methods
}
NOTE: Do not use the path to the file containing the class to be implements, extends of use to instantiate an object but only use the namespace.