Laravel 5 Class extend - php

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.

Related

Create Classes and Derived Classes in any folder of Zend

I want to ask some questions about the Zend framework. if someone knows please answer it will be a great help.
Q1. Can we create classes, abstract and derived classes in any folder
of the Zend Project?
Q2. If Q1 answer is yes how we can database access (from the model
class) or we need to utilize any other Zend related functionality.
Q3. Is it possible to place abstract class and the implementation
of an class within a dedicated folder somewhere within the source
tree?
Q1 - Can we create classes, abstract and derived classes in any folder of the Zend Project?
Yes, you can, but it is not encouraged. Why? Because it would end up in a messy project, with a portion of code in a given location, other code somewhere else, other snippets in a third location.. This will make maintenance more complex than it should be, wasting time searching for the code between all different locations.
For this subject, I suggest you to read the PSR-4 specifications and directives
That being said, let's make this example. You want to create a class OutsideClass, with namespace OutsideCode, in folder outsideFolder.
What you need to do is:
Create in the folder outsideFilder, which will be located in the root folder of your project.
Create the class OutsideClass:
<?php
namespace OutsideCode;
class OutsideClass
{
// ...
// Class properties, constructor and methods
// ...
}
Add the namespace inside the composer.json, so the application will be able to translate a namespace into a phisical location:
"autoload": {
"psr-4": {
...
"OutsideCode\\": "outsideFolder/"
}
}
Run composer dump-autoload to recreate autoload file
End. You can now put all the code you want inside this folder, always respecting PSR-4 directives
Use your new classes from your controller/mappers/forms/validators/...
<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use OutsideCode\OutsideClass;
class IndexController extends AbstractActionController
{
public function indexAction()
{
$outsideClass = new OutsideClass();
}
}
Q2 - If Q1 answer is yes how we can database access (from the model class) or we need to utilize any other Zend related functionality.
It is not mandatory to use Zend related functionalities.
Nobody prevents you to access your write all your code from scratch, using only PHP methods, to access the database, or to validate a phone number, or to send an email. If you want to use Zend functionalities (or classes that you already wrote), just import them with a use statement and the top of the file (as shown in the previous snippet).
The most important thing is always: DRY and don't reinvent the wheel (+this)
Q3 - Is it possible to place abstract class and the implementation of an class within a dedicated folder somewhere within the source tree?
Yes, until its position follows PSR-4 specifications and directives, otherwise it won't be loaded (nor executed)

PSR-4: Autoloader (composer) and extending namespaces ensuring fallback php

I am having a problem with my namespace fallbacks and using PSR-4 loader in Composer.
What I am trying to do is this:
Have a core which can overwritten / extended.
The core is based off an interface.
The directory structure is like so:
site/app/View/Example.php
site/src/ACME/app/View/Example.php
site/src/ACME/app/Interface/View.php
I am not set on this configuration so if you have a better suggestion then go for it.
My composer json is like so for psr-4:
"autoload": {
"psr-4": {
"ACME\\App\\Site\\" : "app/",
"ACME\\App\\" : "src/AMCE/app/"
}
}
I thought this would make ACME\App\Site\View fallback to ACME\App\View if the site one was not found (Note I haven't done the interface part yet...).
My code for site/app/View/Example.php is like so:
namespace ACME\App\Site\View;
class ViewExample extends View {
Which works, when I have site/app/View/View.php as well. That looks like:
namespace ACME\App\Site\View;
class View extends \ACME\App\View\View {
The site/src/app/View/View.php look like this:
namespace ACME\APP\View;
class View {
This one should use the interface (I haven't tried yet).
So what I really want to do is make it so I don't have to have site/app/View/View.php, and I don't have to have site/app/View/Example.php - it can use site/src/ACME/app/View/Example.php.
Sorry I'm new to namespaces so I may not of phrased it very well.
What I am getting at is I thought ACME\App\Site would fallback to ACME\App - it doesn't? Or I am doing it wrong? At the moment it needs all the files in place.
Edit: Turns out I was originally wrong, it is possible to get your example working with PSR-4! You just need to specify an array of directories for namespaces that can be loaded from different places.
Easy solution
{
"autoload": {
"psr-4": {
"ACME\\App\\Site\\": ["app/", "src/ACME/app"],
"ACME\\App\\": "src/ACME/app/"
}
}
}
Personally, I would rather name my namespaces more explicitly, see below.
Original Answer
The composer PSR-4 loader does not fall back when trying to load files that do not exist. It just fails immediately. Its flow looks like:
\ACME\App\Site\View is not loaded
Scan PSR-4 entries for matching namespaces
Class name matches the namespace \ACME\App\Site (your first PSR-4 entry).
Load file app/View.php
File does not exist. Error.
It never goes back to step 3 and tries the next namespace.
So how do I fix it?
It looks like you want to separate your reusable library code from your site code. If that's the case, I would use separate namespaces. For example, use the ACME\Site namespace to hold your reusable code, and use ACME\MySiteName for your site-specific code. Then there will be no ambiguity, and composer will have no trouble loading your classes.
But I don't want to rearrange my namespaces!
Ok, that's fine, but you'll have to use a hack to get around your problem. Composer has a classmap loader, and you'll have to use that instead of the preferred PSR-4 loader.
{
"autoload": {
"classmap": ["app/", "src/"]
}
}
Let's separate the things a bit, because they are all mixed up for now.
What I am trying to do is this:
Have a core which can overwritten / extended.
The core is based off an interface.
This sounds like basic object oriented inheritance. An interface defines the proposed public behaviour, the core implements the needed basics, and the detail implementation changes some parts, and reuses the others.
Let's write your example code in a way PHP sees it with absolute namespace names:
class \ACME\App\Site\View\ViewExample extends \ACME\App\Site\View\View {}
class \ACME\App\Site\View\View extends \ACME\App\View\View {}
class \ACME\App\View\View {}
You have three classes explicitly named. You'd need three files that match the namespace and class name. The autoloading does not need to do any detection whether or not a class is present - because you cannot optionally inherit from a class that isn't there, or omit it otherwise.
On the other hand, implementing three levels of inheritance by default very likely is too much. It looks like bad design to me, and will make maintaining the code harder than necessary. Depending on what you want to achieve, there are plenty of alternatives to get what you want easier. For example, to change some details of behavior, there are the decorator pattern or the strategy pattern.
So what I really want to do is make it so I don't have to have site/app/View/View.php, and I don't have to have site/app/View/Example.php - it can use site/src/ACME/app/View/Example.php.
You cannot have this. Your code explicitly states that it inherits from \ACME\App\Site\View\View, so this class MUST be present somewhere.
This is independent of any autoloading. To experiment, you can add all your code into one single file and then run it. This will make all classes known to PHP immediately, and the problem will become obvious: You cannot remove a class when at the same time other classes inherit it.
Sorry I'm new to namespaces so I may not of phrased it very well.
Namespaces are nothing really fancy, the same problem would arise if you would use the PSR-0 style classnames with underscores:
class ACME_App_Site_View_ViewExample extends ACME_App_Site_View_View {}
// This class MUST be present for the above class to work
class ACME_App_Site_View_View extends ACME_App_View_View {}
class ACME_App_View_View {}
The main new feature with namespaces is that you can import one class under a second name within a file with use OtherNamespace\Classname. But this is only an alias within the scope of this file (i.e. it does not affect other files or the global scope).
Namespaces and autoloading are not the right tool for this job. A namespace is just a way of making sure two people (or parts of your code) don't use the same name to mean different things. Autoloading is just a way to avoid having to list every source file you want to load code from.
When you override the behaviour of one class in another, these are not the same class; often, you'll want to inherit the default actions and reuse parts of them.
You might want to create several sub-classes for different purposes, so you need somewhere to hold the logic of which to use. The component which deals with this is called a "service locator" or sometimes a "DI container".
Namespaces let you map short names to longer, unique class names; autoloading let's you map a specific unique class name to a source file; service location is how you choose which unique class you want to use in a specific circumstance.

Modern PHP Book - Clearification about "use" and "require" when using Namespace

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 {
}

PHP - Symfony2.4 Can I have multiple classes in single file?

I am using Vzaar's PHP Library for uploading videos from my website to their server space.
Now point is - in their library there are some PHP files in which more than one class exists and no class with same file name exists in same file.
i.e. have a look at OAuth.php, there is no class with name OAuth in that file.
Question raised in my mind is
When I create any PHP class file, can I create multiple classes in side one file, and later I can use that file in my code or I can use that reusable code in other project as well.
Should creating such files is good practice?
If the class is of 15 to 20 lines long, then should I create a separate file or I should include that in one file only, like OAuth.php.
Please guide with exact reason, if I will get links of wiki where proper explanation is given, then it will be best.
Putting more than one class in one file in general is a bad practice, and in Symfony2 even more because of the way class autoloader works.
When autoloader is looking for Acme\DemoBundle\SomeClass class it expects it will be in Acme\DemoBundle\SomeClass.php file. So in case you have a second class in the same file it won't work.
Check also PSR standards for class autoloading.
Despite I don't like to define more than one class per file I would like to point it out that PSR-4 is not against this practice if the class scope is private.
Quoting Symfony2 coding standards resource (http://symfony.com/doc/current/contributing/code/standards.html)
Define one class per file - this does not apply to private helper
classes that are not intended to be instantiated from the outside and
thus are not concerned by the PSR-0 and PSR-4 autoload standards;
In this other example (Thanks to Xavi Montero) you can see that the class Psr4AutoloaderClassTest has a helper class MockPsr4AutoloaderClass defined in the same file. So in general you should not, but for a "private helper" it's okey.
https://www.php-fig.org/psr/psr-4/examples

Composer Overriding/Extending Classes With Namespaces

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

Categories