Hey everyone I'm making a little webiste with the silex php microframework and I have a problem that I can't understand! So here is my question !
If I use this at the top of my main php file :
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
and then I later require these files :
require 'phpFiles/login.php';
require 'phpFiles/register.php';
Why can't i use the top classes in the code of my required class ?
I dont want to add these 2 use line to every single php file I require
Hope you guys understand my question !
It's not like you "can't use the top classes" in the included files. It's just that the included files don't inherit the parent file's importing/aliasing rules defined with use because those are per-file basis only. If you want to be able to refer to Symfony\Component\HttpFoundation\Request with just Request in the included files, you need to use use in those as well. Your only other option is using fully qualified names.
Related
I have this in my controller:
if (!defined('BASEPATH'))
exit('No direct script access allowed');
use xampp\htdocs\client\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Spreadsheet;
use xampp\htdocs\client\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Writer\Xlsx;
But here is the error I am seeing after running the code
Message: Class 'xampp\htdocs\client\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Spreadsheet' not found
Filename: C:\xampp\htdocs\client\application\controllers\admin\Home.php
You appear to have confused use and include/require.
A use statement is for namespace importing and aliasing. It says "when I use the class name Foo, what I actually mean is Something\Something\Foo. That full name may look like a Windows file path, but the \ here is actually PHP's namespace separator, and doesn't directly relate to the location on disk.
In this case, you would write:
// Alias these class name so I don't have to write them in full in this file
use PhpSpreadsheet\Spreadsheet;
use PhpSpreadsheet\Writer\Xlsx;
If you want to reference the code in a particular file, you need the include and require family of keywords. Those say "load this PHP file, and execute the code in it, including class and function definitions.
So the following would make sense:
// Load the file
require_once 'xampp\htdocs\client\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Spreadsheet.php';
require_once 'xampp\htdocs\client\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Writer\Xlsx.php';
However, most PHP libraries are built to be autoloaded, so you don't have to name each file manually. Generally, you don't even need to configure the autoloading itself, instead you'd use Composer to install them, and it would set up the autoloader for you.
You would then write, in the main entry point of your code:
require_once 'vendor/autoload.php';
And the classes would be loaded automatically when referenced. Note that you probably still want the use lines, though, and those do have to be in each file (because each file can use the same alias to reference different classes).
I dynamically generate my use statements and try to include them.
use.php (Path: /App/Test/Use/use.php)
<?php
use App\Http\Utility\GeneralUtility;
use App\Models\Project;
use App\Http\Selenium;
?>
PlayController.php (Path: /App/Http/Controllers/PlayController.php)
<?php
namespace App\Http\Controllers;
require app_path() . '\Projects\Test\Use\use.php';
...
However, If I try to use a included/required class in my controller then I get the info that some classes are missing. E.g.
FatalThrowableError in PlayController.php line 30:
Class 'App\Http\Controllers\Selenium' not found
Of course it works If I write them manually into the Controller without using require:
<?php
namespace App\Http\Controllers;
use App\Http\Utility\GeneralUtility;
use App\Models\Project;
use App\Http\Selenium;
...
So why does it not work if I include / require them?
It is not possible what you are trying to do.
Here is the documentation from the PHP manual on it:
Note: Importing rules are per file basis, meaning included files will NOT inherit the parent file's importing rules.
The source comes from here and the full documentation link is here.
Use is done at compile time and include at runtime, so that makes it impossible.
But what you could do is, use something like PHP-Parser to replace the includes before the script is being executed.
I got a simple question for you hopefully. Can it be possible that I just initialize the namespace for a class once in my "main file" and all other objects or classes got the same reference of it ?
For example Index.php:
require_once 'init.php';
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
and now I got a class not in the same file with this kind of code. Controller.php:
function programmAction($id) {
$programm = $this->model->getProgrammById($id);
$html = $this->renderTemplate($this->tempProgramm,['programm' => $programm]);
return new Response($html);
}
Normally when I don't add the use lines as well to this file I would get an error message that the class Response was not found.
Only if you include all other classes in the same file. Refer to this note from the manual:
Note:
Importing rules are per file basis, meaning included files will NOT inherit the parent file's importing rules.
Please don't include all of your classes in one file.
It may seem like a pain to retype the use statements in each and every class file, but really it will help you when you go back and refer to that file later. Right at the top is a list of classes that your class depends on, and could be helpful information during a refactoring or code reorganization.
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'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);