I'm trying to include many files containing functions, classes and calls but I would like to put everything in a PHP namespace.
My issue is : all the files are part of another web application core. So I cannot edit the files.
Is there a way tu declare a namespace globally for a list of files ?
Something like that :
namespace mynamespace {
include_once("file1.inc.php");
include_once("file2.inc.php");
include_once("file3.inc.php");
...
}
Of course I tried this code and it does not work; all my tries failed while the first line of the include files where note namespace mynamespace;.
No, it is not possible. Every single file needs to declare its own namespace; you cannot force something to be in a different namespace using external code. (Some hacks like runkit or such will probably allow you to fiddle with that, but I'd consider this outside the regular scope of PHP as a language.)
Yes. A bit cumbersome (you need to list all classes) and works only if you have well behaved files that start with <?php and don't have a namespace in them. Also, because there's no decent error-reporting in eval'd stuff, use it only with well tested code.
<?php
namespace whatever;
use mynamespace\Class1FromFile1;
use mynamespace\Class2FromFile1;
use mynamespace\ClassFromFile2;
use mynamespace\ClassFromFile3;
function ns_inc ($lib, $ns) {
eval("namespace $ns;" . substr(file_get_contents($lib), 5));
}
$ns= 'mynamespace';
ns_inc('file1.inc.php', $ns);
ns_inc('file2.inc.php', $ns);
ns_inc('file3.inc.php', $ns);
Related
This is what I have at hand:
//Person.php
namespace Entity;
class Person{
}
User file:
//User.php
use Entity\Person;
$person = new Person;
Here, it fails if I don't include the Person.php file. If I include it, the everything works fine. Do I absolutely require to include the file even when using namespaces? If at all we need to include/require files, then how can namespaces be effectively used? Also, can we maintain folder structure by nesting namespaces?
The answer to your question is "yes and no".
Indeed the code implementing class Person has to be included, otherwise the class is not defined and cannot be used. Where should the definition come from, when the code is not included? The php interpreter cannot guess the classes implementation. That is the same in all programming languages, by the way.
However there is something called Autoloading in php. It allows to automatically include certain files. The mechanism is based on a mapping of class names to file names. So in the end it boils down to php searching through a folder structure to find a file whos name suggests that it implements a class currently required in the code it executes.
But don't get this wrong: that still means the file has to be included. The only difference is: the including is done automatically, so without you specifying an explicit include or require statement.
Yes, you need to include every file.
A very good example can be found here on effective usage of namespaces.
With PSR-0 autoloading, the namespace has to be the same as the folder in which the class is, file the filename has to be the same as the classname. This gives you very simple and effective autoloading with composer for example.
I've been reading a lot of posts on StackOverflow but I'm not really sure I'm using namespaces, autoloading, and aliasing correctly. This is functioning fine, but I'm not sure I'm properly using these concepts. I've listed some reasons why I think this setup is incorrect at the bottom of the post.
Imagine the following directory structure:
\public_html
- index.php
\Classes
\A
- One.php
\B
- Two.php
One.php is structured like:
<?php
namespace Classes\A;
class A { ....
Two.php is structured like:
<?php
namespace Classes\B;
class B { ....
Then, in index.php I do something like:
<?php
use Classes\A\One as One;
use Classes\B\Two as Two;
spl_autoload_register(function ($className) {
...
});
... ?>
So, a couple things that bug me about this:
If I am doing aliasing (the "use" statements) I still need to list out all of the files. Aren't we trying to avoid doing this by using autoload?
If I want to use internal classes, I need to add a line such as "use \mysqli;" into the class that uses this and do things like "new \mysqli()". Seems kind of messy?
If a class extends a class from another namespace (say Two.php extends One.php for example) then I need to include "use \Classes\A\One as One;" in One.php which seems to be what we want to avoid in the first place
You don't have to reference all of your namespaced classes via a use statement. You can use partial namespaces.
use Classes\A;
new A\One();
So you can see if you had another class in the A namespace it could be instantiated with
new A\Three();
There are many things in the global namespace, you don't need to define them with use. You can just call them \mysqli(). Yes it's a bit unsightly but it allows you to make a function called mysqli in your own code without worrying about collisions with globally namespaced functions.
I'm not sure I follow you on this one. You don't need to do a use in the base class which references itself.
Ultimately it kinda seems like you view use almost like include when they are very different, use, in this context, is a convenience thing so you don't have to type out full namespaces every time.
Your Autoloader also doesn't need to know about your namespaces. The autoloader just tells PHP how to load a class. So if it sees a class come in with the name Classes\A\One you can make it look in the directory /Classes/A for a file called One.php and include it. PHP will make sure that the class is allocated in the proper namespace. The autoloader is just a convenience thing to keep you from having to do includes and requires in each of your PHP files.
I include myfile.php file 2 times.. I want to know if there is way to put in the start of myfile.php something like this:
if($authorized){
Namespace MyProject;
}
function ABC(){}
function EFG(){}
(I do this to avoid function-redefine errors. Please dont ask me why I do such thing.. I know there are if function_exists and etc.. but I need answers to what I ask).
update:
I do this, because I need to define function XYZ() and using that before other framework is loaded (which newly defines globally function XYZ()). So I want to use that function (with different functionality) before framework loads, and after framework loads, it should behave as framework decides.
Is there a way to make namespace's conditional?
Although this is impossible directly, I could suggest using the define() method to create this yourself. Where the file requiring the class needs to have a allowed definition to access the file.
define('IN_NAMESPACE', 0);
if(defined('IN_NAMESPACE')) {
// authorized
}
But if you're worrying about a class name being repeated, namespaces are for the declaration of environments so you do not get duplicates, for example:
namespace Environments\One;
class Example { }
namespace Environments\Two;
Class Example { }
use Environments\One\Example as ExampleOne;
use Environments\Two\Example as ExampleTwo;
$e_o = new ExampleOne();
$e_t = new ExampleTwo();
Or simply, directly say you will use this environment like so:
$e_o = new Environments\One\Example();
$e_t = new Environments\Two\Example();
But again, this issue is not canonical to PHP. Use MVC methodologies to over-come these issues and Singleton/Dependency Injection design patterns.
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.
I am trying to figure out how to use the namespace in php. I have been reading about how to use it and for some reason I can not get it to work. I have two files one which I have stored in Applications/Database/Classes file name is DatabaseConnection.php and the other in the root directory called DB.phpinside the DatabaseConnection.php file I have the following code:
<?php
function hello()
{
echo "hello";
}
?>
This is the DB.php file contents:
<?php
namespace Applications\Database\Classes;
ini_set('display_errors', true);
hello();
?>
Maybe I am completely missing how to use it properly but if I set a namespace is that the same as using include or require? I might be completely misunderstanding how to use it. I am new to OOP and have never heard of namespaces until I started trying to learn OOP? Can someone point out what I did wrong.
Namespaces are for organizing your code in so that you can divide components up and help with the readability. For example if I have a class Pittbull and another Dashund I can place them into a namespace like so for organization:
Animals.Dogs.Pittbull
Animals.Dogs.Dashund
This also helps with potential collisions like the below:
Animals.Dogs.Misc
Animals.Cats.Misc
The Misc class exists twice in this instance, but instead of there being a conflict of which Misc to use, you can use the same class name for both classes (and have different properties and methods inside of them) and not have a conflict of which one you want to use.
The require keyword is a completely different concept and is used to load actual files into the executing script.
Instruction how to use autoloading in PHP (PSR-0):
https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md