So I need to include modular code/libraries in my project, a new library:
Library A:
a.php: class A;
Library B: (with v1.0 checked out from A)
b.php: include_once a.php; class B extends A;
Library C: (with v2.0 checked out from A)
c.php: include_once a.php; class C extends A;
Library D:
d.php: include_once b.php,c.php;
This obviously leads to name conflict (cannot redeclare A).
I cannot touch either of the libraries as they are frequently pulled from elsewhere. Also, I need the result to be another library, so nested namespaces is not an option. But I guess there must be plenty of other projects with the same problem?? Thanks for any suggestions.
You can use require_once or include_once, in place of your includes.
These may affect performance, as memory and processing has to be used to keep track of included classes and check against it, but it's the easiest solution. How much they do, depends on how many include/require_once are in your single page load.
More complicated ones would implement a class autoloader, but you might not want to go there...
EDIT--
If I understand well your problem, it's a dependency problem. Libraries B and C both refer to A, but each refers to a different version of A. If that's the case, the solution is not trivial: any use of require_once or include_once will lead to undetermined first loaded version of A to be used. Any use of include will result in class duplication. I don't think you can solve the issue by just using these functions. What you'd need to do would be to manage library dependencies.
For example, an autoloader that recognises several versions of a class library and loads the most recent one (this assuming that you keep backwards compatibility across versions). You could also try to use nested classes, to keep each library's dependencies isolated and self-contained.
You can check if a class got declared already, in case your filenames are different for each version.
Example:
if (!class_exists('A')) {
include a-XX.php;
}
Note that this way you only load one version of your class.
If I understand you well
your problem is that
Library B And C includes the same file which is A
And you want B And C In D in the other B and C which has the same file
which is A so it shows
Fatal error: Cannot redeclare class A in
ok --->
in files c.php , b.php And d.php include_once 'a.php'; OR
require_once 'a.php';
Related
This is my project path configuration
./create.php
/Install/Install.php
create.php
<?php
use Install\Install;
echo "Starting";
$install = new Install();
This gives me the error
PHP Fatal error: Uncaught Error: Class 'Install\Install' not found in /project/create.php:6
Install.php
<?php
namespace Install;
class Install
{
//whatever
}
Can someone explain me what is happening there ?
Obviously I guess that using a require_once line with my filename would probably fix the issue...but I thought using namespace and use import could prevent me from doing that like we do in classic framework like symfony / magento ?
I've seen some post speaking about autoloading, but i'm a little bit lost. Haven't been able to find a clear explanation on the other stack topic neither.
PHP compiles code one file at a time. It doesn't have any native concept of a "project" or a "full program".
There are three concepts involved here, which complement rather than replacing each other:
Namespaces are just a way of naming things. They allow you to have two classes called Install and still tell the difference between them. The use statement just tells the compiler (within one file) which of those classes you want when you write Install. The PHP manual has a chapter on namespaces which goes into more detail on all of this.
Require and include are the only mechanisms that allow code in one file to reference code in another. At some point, you need to tell the compiler to load "Install.php".
Autoloading is a way for PHP to ask your code which file it should load, when you mention a class it hasn't seen the definition for yet. The first time a class name is encountered, any function registered with spl_autoload_register will be called with that class name, and then has a chance to run include/require to load the definition. There is a fairly brief overview of autoloading in the PHP manual.
So, in your example:
use Install\Install; just means "when I write Install, I really mean Install\Install"
new Install() is translated by the compiler to new Install\Install()
the class Install\Install hasn't been defined; if an autoload function has been registered, it will be called, with the string "Install\Install" as input
that autoload function can then look at that class name, and run require_once __DIR__ . '/some/path/Install.php';
You can write the autoload function yourself, or you can use an "off-the-shelf" implementation where you just have to configure the directory where your classes are, and then follow a convention for how to name them.
If you want to Use class from another file, you must include or require the file.
Use require('Install.php'); before use Install\Install;.
If you are planning to do a big project I would recommend to use PHP frameworks rather than coding from scratch.
I've seen a lot of threads here and in other forums that asked this a lot of times, but I still see using the include function of PHP in the answers?
how can I use this function, not using totally the include function?
Thank you
how can I use this function, not using totally the include function
You cannot totally not use include and that is not the point of using autoloader as you usually need to at least include the autoloader ;). That autoloader is the regular PHP code that is being called by PHP when unknown class use is attempted in the code. It is expected to include right file to make the class known, and the code continues as you'd explicitely include right file by hand in your code. So the main benefit shows up when your code uses classed (OOP) - you do not need to care if you included the class you are about to instantiate the object of or not. You just do new Foo() or call Something::methodName() and if all is set up right it will work.
The function spl_autoload_register is used to register a callback into the autoloader queue.
The PHP autoloader is a functionality of the PHP interpreter that, when a class is not defined, calls the functions registered in the queue, one by one, asking them to load the class, until the class becomes available. It the class is still not available after all the functions were invoked, the interpreter triggers a fatal error.
The autoloader doesn't perform any magic. It is the entire responsibility of the registered functions to make the class available. Most of them use the name and namespace of the missing class to figure out the path of the file that contains the declaration of the class and include it.
That's how the thing works. There are not many ways to produce a class in PHP and, for a reusable autoloader callback, the list starts and ends with include1 (include_once, require or require_once can be used as well but they don't make any difference in this case.)
The autoloader callback itself stays in separate file (for reusability) and usually that file also contains its registration as autoloader callback (the call to spl_autoload_register). All your code have to do is to include this file once in every file that is an entry point of your application.
All things being equal, your application needs to use include at least once and once is also the maximum required number of usages for it. The autoloader callback also uses include (probably also only once) but you don't write autoloader callbacks every day. If you wrote one and you wrote it well you can reuse it. Most people never wrote an autoloader callback and they will never write one.
Using Composer is easy and if you follow the PSR-4 rules of naming the files of your project, Composer can generate an autoloader for your project that knows how to load your classes (behind the scene it uses include, of course). All you have to do is to run composer init in the root directory of your project, run composer install and write include 'vendor/autoload.php'; in the file that represents the entry-point of your application. No other uses of include are required.
1 An autoloader callback is not required to include another file to make the class available. It can generate the code of the class on the fly and eval()-uate it, but the use cases of such approach are very limited. It is used by the testing suites f.e., to generate mock classes.
I'm a beginner to L5. I read the documentation about extending classes but i didn't find any information about where to put the file in which i extend the class.
**I have to extend Str.php class. I have read that in L4 it had to be done by putting that file under App/folder but i didn't find that folder in L5.
So please can you tell me how can i do that?
This is the information i have now:
First, you must find where the class file is. We will be extending the Str class, which is under vendor/laravel/framework/src/Illuminate/Support. Note that you can also find this class under the aliases key in app/config/ app.php.
Now create a new folder called lib under app/folder. This folder will hold our class extensions. Because the Str class is grouped under the folder Support, it is suggested that you create a new folder named Support under lib too.
Now create a new file named Str.php under app/lib/Support, which you've just created:
But this is for L4
That's more of a general PHP question and there are two parts: 1) How to extend a class and 2) where to put files.
1) Extending classes isn't something Laravel or anyone else provides. That's right there in the language:
class A {}
class B extends A {}
As long as class A exists and is available, then class B can extend from it.
2) Where the files are is also important here. If you're defining class B and want to extend class A, the php runtime needs to know where to find A. Usually class A isn't defined in the same file as class B.
There are many ways to do this. You could require or include class A when you define class B. That would look something like:
a.php
class A {}
b.php
require "a.php";
class B extends A {}
Now with a lot of files like in the Laravel framework or any worthy library, you're going to have a lot of files to include and have to keep track of how to include those files. That's no fun. So, instead of doing that, PHP has provided a way to autoload the classes. That is, if you define classes in a predictable way, PHP can figure out what classes you're talking about without you having to use require or include statements.
There are also many ways of autoloading php files. In Laravel (and many, many other projects), the composer autoloader is used.
This means that files have to be placed in a pre-defined way in order for the composer autoloader to find them. By reading about the composer autoloader and then digging into the code to see how Laravel's classes are autoloaded, you'll be able to figure out how that happens.
Despite the intricate detail of Peter's answer, I figured I'd write something much more concrete: it doesn't matter.
If you check composer.json, you'll see that we are autoloading everything that is placed inside the app directory anyway. Hence, the choice is really yours. All that matters is that you maintain a sensible and readable structure. For example, you could place it in app/Lib, and namespace all your classes App\Lib (if App is your base namespace of course, which can be changed with php artisan app:name). Of course, you could also have a folder like Helpers/Lib for your extended classes, and keep some form of helpers.php with global helper functions in Helpers.
Why would you do this? Well, you might want to have an easy way to call your new Strfunctions, so instead of having to do Str::yourNewMethod($argument) everywhere, you could add a helper function yourMethod($argument) to easier call the function (if you intend to use it extensively).
One thing you have to remember though, as mentioned by Peter, is that the class you are extending won't automagically be found. It will, however, be autoloaded. Hence, to reference it you have to remember to namespace it, such as in the example below.
<?php namespace App\Helpers\Lib
Class Str extends \Illuminate\Support\Str {}
Also remember to namespace correctly when you call your own class.
I stated implementing object oriented design into my website. I'm using php, and ran into an issue.
As is my tendency, I like to define one class per one file - nothing else. Normally, if I remember correctly, in most languages classes can be called if they're in the same directory without having to be explicitly linked to the main program (I could be wrong, or unique to virtual machines).
Right now, php sends errors when I don't link the class file to the main file. On top of that, a child class won't execute unless I define the link to the parent's class file.
Do I have to explicitly link all of my files together?
Here's some snippets of my code for detail:
<?php
include_once 'VRC_Header2.php';
include_once 'UserService.php'; //Child class file of DB_MySQL.php
include_once 'DB_MySQL.php'; //Parent class
//Without the two links above, this file will not execute
Then the child class:
class UserService extends DB_MySQL
{...
Any help is appreciated.
Yes, in PHP, you have to include all classes you need before you instanciate them.
One method to circumvent this is to use autoloading:
http://php.net/manual/en/language.oop5.autoload.php
Which is used on most PHP Frameworks (e.g. Zend Framework).
You have to include all class files to one another. Otherwise other pages will not understand where the class is present.
You can use namespace concept.
http://php.net/manual/en/language.namespaces.php
But in this you have to include the class files.
I had a problem recently with a php project that I finally realised was down to the way I had structured my classes. If I tried to include more than one class in a page and both classes shared the same parent class, the script failed. I've now resolved the issue but was wondering if someone could explain to me exactly why what I was doing wasn't working, cos I haven't quite got my head around it!
Here's an illustration of what did NOT work:
class A.
class B extends A.
class C extends A.
class D extends B.
class E extends C.
I require class D and class E and the script fails. If class C does not inherit A then it all works fine.
Obviously, it's something to do with requiring class A twice, but could someone explain it in very simple terms for me?!?!?
You may declare every class only once. If you require the file where your class is defined more than once, the parser encounters the class A, makes an internal lookup and bails: 'Hey, you've already defined that class'. The most simple solution is to put every class into its own file and call require_once instead of require.
Do you have each class in its own file?
Are you using require/include instead of require_once/include_once ?
include_once and require_once do not share the same table of included files either, so you have to use one consistently.
Or consistently use the __autoload function in PHP5.
Any functions or classes defined in included files are declared in the global scope. This is why you are probably getting redeclaration errors. The solution is to use require_once or include_once instead of require or include.
The most elegant way though, is to use a __autoload, but that requires PHP version 5 or later. The only downside to autoloading is that any failure is a fatal error which you can't handle yourself.