I have a question about extending a class in PHP.
The examples I see on the php site just have 1 line of code in the method...is it the same if the method has tons of code??
If this is the base class:
class BaseClass {
public function WithWayTooMuchCode {
// like 100 lines of code here
}
}
Then do I have to copy all the code over if I want to use the same method, but change only 1 or 2 things?
class MyOwnClass extends BaseClass {
public function WithWayTooMuchCode {
// like 100 lines of code here
// do I have to copy all of the other code and then add my code??
}
}
This seems a little not DRY to me...
Yes, unless those 1 or 2 things happen to be at the beginning or the end. You can call the parent function via
parent::WithWayTooMuchCode();
Which you can place anywhere in the child/overridden method.
If it doesn't feel DRY, consider splitting the function into smaller methods.
do I have to copy all the code over if I want to use the same method,
but change only 1 or 2 things?
No, you don't have to copy all of the code, assuming you're adding to the function and not removing pieces of it.
so it follows:
class BaseClass {
public function WithWayTooMuchCode {
// like 100 lines of code here
}
}
class MyOwnClass extends BaseClass {
public function WithWayTooMuchCode {
parent::WithWayTooMuchCode();
//additionally, do something else
}
}
$moc = new MyOwnClass();
$moc->WithWayTooMuchCode();
You can use the parent::WithWayTooMuchCode() wich will execute the parent method and after you can add your code. It will look like this :
class MyOwnClass extends BaseClass {
public function WithWayTooMuchCode {
parent::WithWayTooMuchCode()
// do I have to copy all of the other code and then add my code??
}
}
You can write down a separate function for that things that you want to do separately in parent class and then Call then in you way.
In other words, separate out the things you need to do separately ans create a function for them. And call them separately in child class. The final function in child class will call parent class function as well those separate functions.
You have a few choices. Assuming;
class BaseClass {
public function WithWayTooMuchCode {
// like 100 lines of code here
}
}
You can do
class MyOwnClass extends BaseClass {
public function AnotherFunction() {
// put other code here
}
}
This allows you to do MyOwnClass->AnotherFunction() and MyOwnClass->WithWayTooMuchCode()
or you could do
class MyOwnClass extends BaseClass {
public function WithWayTooMuchCode() {
// put new code here
}
}
which will allow you to run MyOwnClass->WithWayTooMuchCode() and will ONLY run the "new code", not the "100 lines".
Finally you could do
class MyOwnClass extends BaseClass {
public function WithWayTooMuchCode() {
parent::WithWayTooMuchCode();
// Do more processing
}
}
which will allow you to run MyOwnClass->WithWayTooMuchCode() will run the "100 lines of code" AND the new code. You can put the parent before/after/during your new code, so you can tailor it as required
In addition to the other answers I should point out that this problem can be addressed by events. They are a way to determine points in a class where you can add your own functionality from outside. If you have control over the codebase and the time/inclination you might want to consider implementing this functionality. Unfortunately PHP doesn't support them directly in the way that, say, C# does so you'd have to do the work.
If you only have this issue in a single place I doubt you should bother, but if it's becoming a pattern you might want to consider this approach.
Related
I have a class called PdfRenderer
class PdfRenderer
{
function __construct(Fpdi $pdf)
{
$this->pdf = $pdf;
}
}
I also have a class PdfProposalRenderer
class PdfProposalRenderer extends PdfRenderer
{
function __construct(Fpdi $pdf, array $filename)
{
parent::__construct($pdf);
}
}
I need to make a change to the PdfRenderer class, by adding a new parameter in the constructor:
class PdfRenderer
{
function __construct(Fpdi $pdf, StreamFactory $streamFactory)
{
$this->pdf = $pdf;
$this->streamFactory = $streamFactory;
}
}
Normally, after this change I search the codebase for any occurrences of "new PdfRenderer", and if there are any, I update instantiation parameters in those places. That's all that needs to be done, right? Is there anything else? Usually no? So that's where I usually stop.
Well now, here lies the problem .. I have a lot of classes, I don't always remember that ...
In my case PdfProposalRenderer extends PdfRenderer", so I need to go to PdfProposalRenderer and into construct method to update the parent::__construct($pdf) line to match the change I've made in the parameters of PdfRenderer
Also, are there any other classes that extend PdfRenderer? Maybe, I have to check, now that I am aware of this.
But generally I don't run such checks, so this type of change goes missing, until PdfProposalRenderer breaks in live code.
Question
Is there a way to modify the code in the constructor of PdfProposalRenderer or in other places, to where when I update constructor parameters in PdfRenderer, it is more painfully obvious that I need to change it in those places too?
For example, is there a way to modify the code in PdfProposalRenderer's constructor say new PdfRenderer`?
If not, are there any other ways to check for that change, other than searching the codebase for " extends PdfRenderer" and then checking for any "parent::__construct" lines of code?
Implementing MER's suggestion:
Leaving PdfProposalRenderer alone and doing this:
class PdfRenderer
{
function __construct(Fpdi $pdf, StreamFactory $streamFactory = null)
{
$this->pdf = $pdf;
$this->streamFactory = $streamFactory ?? new StreamFactory();
}
}
Also, in PdfProposalRenderer I've decided to call out the parent class by name, so instead of
parent::__construct($pdf);
I used
PdfRenderer::__construct($pdf);
So, I've got a question that, while based in Laravel, might just end up being something basic in PHP that I either missed or forgot. Or it may just turn out there is no "textbook/clean/standard" way of doing it.
A Question of Clutter
Anyway, I'm creating a fair number of Form Requests in Laravel (it's a sizable "app") and I'm constantly struck by how unnecessarily redundant their inclusion can be:
<?php
namespace App\Http\Controllers\Account;
use App\Http\Requests\SubscriberRequest;
use App\Http\Requests\SubscriberUpdateRequest;
use App\Http\Requests\SubscriberExtRequest;
use App\Http\Requests\SubscriberExtUpdateRequest;
class MailingListController extends BaseController
{
public function store(SubscriberRequest)
{
// code here
}
public function update(SubscriberUpdateRequest)
{
// code here
}
public function ExtCreate(SubscriberExtRequest)
{
// code here
}
public function ExtUpdate(SubscriberExtUpdateRequest)
{
// code here
}
}
The Alternative
Putting it up above moves the clutter out of the controller itself, but ends up being more work to create and maintain. I'm finding it's easier to just do it like this:
<?php
namespace App\Http\Controllers\Account;
class MailingListController extends BaseController
{
public function store(\App\Http\Requests\SubscriberRequest)
{
// code here
}
public function update(\App\Http\Requests\SubscriberUpdateRequest)
{
// code here
}
public function ExtCreate(\App\Http\Requests\SubscriberExtRequest)
{
// code here
}
public function ExtUpdate(\App\Http\Requests\SubscriberExtUpdateRequest)
{
// code here
}
}
The Question
Obviously, either of these ways is "fine" and "valid." This is hardly a high-priority issue. But the form requests are all coming from the same namespace. And when I'm working with a couple dozen controllers, the typing/copying can get tedious.
So, with all that in mind, is there an "ideal" PHP class-based solution to this problem? And, failing that, should I resort to an app-wide constant/variable? (Or is there some other trick anyone would recommend?)
If you are using php 7+
Here is a nice way to keep your namespace inclusion cleaner.
use some\namespace\{ClassA, ClassB, ClassC as C};
I'm in the process of trying to track outdated or unused functions inside an object class. One idea I had was to create a new class that inherits that original class, and then "track" when that parent's functions are called. When detected, I will migrate the parent's function into the child until eventually only the necessary/needed functions exist.
Is there code that does this automatically within PHP? Here is in example.
class OldUser {
function getFullName() {
return "{$this->firstName} {$this->lastName}";
}
}
class User extends OldUser {
}
-----
$user = new User;
echo $user->getFulLName();
Then in a log somewhere I note:
"{timestamp} function getFullName() called"
Obviously I could add these logs manually, but if there is an existing way for PHP to do it I'd love to default to that methodology.
Alternatively, if there is a better way to do this I am open to suggestions.
Thanks!
If your code is too magic for static code analysis tools, you should probably write some integration/functional tests for your app and take a look at code coverage - non-covered methods may be a dead code (or you need more tests). After this you will not only have cleaner code, but also useful test, so two birds with one stone. :)
One possible way to achieve this without having to manually add the calls is to use a class that doesn't inherit the class you want to track/log:
Something around these lines should do it:
class User{
private $old_user;
// use the same signature of your class constuctor here
public function __construct($arg1, $arg2, ...)
{
$this->old_user = new OldUser($arg1, $arg2, ...);
}
public function __call($name, $arguments)
{
log(sprintf("%s: function %S() called", date('Y-m-d H:i:s'), $name));
call_user_func_array([$this->old_user,$name], $arguments);
}
}
All you need to do from there is implement all of the public methods of OldUser and have those calls trigger the logging and then call the parent function. eg:
class User extends OldUser {
protected function log($method, $backtrace) {
// ...
}
public function getFullName() {
$this->log(__METHOD__, debug_backtrace());
return parent::getFullName();
}
}
debug_backtrace() will allow you to track down where in the code that the function was called.
I'm working on a tool exporting tests as PHP/PHPUnit and I'm facing a small problem. To explain briefly, the test scripts only contain calls to an actionwords object, which contains all the logic of the test (in order to factors various steps from different test scenario).
An example might be clearer:
require_once('Actionwords.php');
class CoffeeMachineHiptestPublisherSampleTest extends PHPUnit_Framework_TestCase {
public $actionwords = new Actionwords();
public function simpleUse() {
$this->actionwords->iStartTheCoffeeMachine();
$this->actionwords->iTakeACoffee();
$this->actionwords->coffeeShouldBeServed();
}
}
Here in the coffeeShouldBeServed method, I need to run an assertion, but that's not possible as the Actionwords class does not extend PHPUnit_Framework_TestCase (and I'm not sure it should, it's not a test case, just a set of helpers).
Currently the solution I found is to pass the tests object to the action words and use the reference for the assertions, something like that.
class CoffeeMachineHiptestPublisherSampleTest extends PHPUnit_Framework_TestCase {
public $actionwords;
public function setUp() {
$this->actionwords = new Actionwords($this);
}
}
class Actionwords {
var $tests;
function __construct($tests) {
$this->tests = $tests;
}
public function coffeeShouldBeServed() {
$this->tests->assertTrue($this->sut->coffeeServed);
}
}
It works fine but I don't find it really elegant. I'm not a PHP developer so there might be some better solutions that feel more "php-ish".
Thanks in advance,
Vincent
The assertion methods are static so you can use PHPUnit_Framework_Assert::assertEquals(), for instance.
This is the basic class design
class CustomModule {
public __construct() { }
//Run me first automaticly
public function exec($str) { }
}
class Randomizer extends CustomModule {
public __construct() { }
//Call me
public function exec($str) { }
}
As I am designing a plugin/module system for extern developers I need the CustomModule->exec() to run first, I do not want to leave it up to the devs to have to call base->exec($str).
I want CustomModule::exec() called automaticly before Randomizer::exec() is called without having to put code in Randomizer::exec(). Is This Possible perhaps with magic function?
In my opinion, i would use this way:
Instead of calling _construct in exec of Randomizer, you can define a constructor in Randomizer and call parent::_construct
class CustomModule {
//Run me first automaticly
public function exec($str) { }
public __construct($str) {
$this->exec($str);
}
}
class Randomizer extends CustomModule {
//Call me
public function exec($str) {
parent::__construct($str);
}
}
If your object requires some initialization before you can "release* it into the rest of application, then it means that you need a factory for this. This is how you should be solving it, if you require to call some method only once.
If such execution happens each time you call exec() method, then instead you should be using some sort of containment (in a form of decorator or just you standard composition of objects).
Basically, you need to restructure your code.
After a bit more thought I realized this is BAD design. I have to keep the code base simple and scaleable and this would only make a mess in large projects.
As the only program calling the Randomizer::exec() is my inhouse built program I can just call CustomModule::exec() on the previous line and get a boolean response to see if it should continue to the next line.
Sorry to have to end this Q' short