I am learning OO PHP and I was experimenting with using a parent::method in a child class. I noticed i had to use an "extra" return for the output of the parent method to show up. Could someone explain me why this is?
This is the code I used and in the code I made a comment.
class ShopProduct {
public $productnumber;
public function __construct($productnumber) {
$this->productnumber = $productnumber;
}
public function getSummary(){
return $this->productnumber;
}
}
class BookProduct extends ShopProduct {
public function __construct($productnumber) {
parent::__construct($productnumber);
}
public function getSummary() {
return parent::getSummary(); // if i dont use return it doesnt work? why is that?
// parent::getSummary(); is not enough it seems.
}
}
$product = new BookProduct(11111);
echo $product->getSummary();
?>
public function getSummary() {
return parent::getSummary(); // if i dont use return it doesnt work? why is that?
// parent::getSummary(); is not enough it seems.
}
Replace parent::getSummary() with any other function or method call:
public function getSummary() {
foo();
}
Of course you wouldn't expect getSummary to return anything in this case, right? Just because the method you're calling is parent::... doesn't change anything about this behaviour. It does not return automagically, because you may want to do something like this:
public function getSummary() {
$summary = parent::getSummary();
return "Book: $summary";
}
BTW, if the only thing your method does is call its parent, you can leave out the entire method. In other words, this:
class BookProduct extends ShopProduct {
public function __construct($productnumber) {
parent::__construct($productnumber);
}
public function getSummary() {
return parent::getSummary();
}
}
is exactly the same as this:
class BookProduct extends ShopProduct { }
Related
I am so lost with how to get this working. All I want to do is to be able to call a function from another class and return the value.
in livewire component
use Livewire\Component;
use App\Actions\Broadcast\GetCurrentActiveTimeSlotAction;
class DisplayLiveBroadcastCard extends Component
{
public $timeSlot;
public function mount()
{
$this->refreshTest();
dd($this->timeSlot);
}
public function refreshTest()
{
$this->timeSlot = GetCurrentActiveTimeSlotAction::execute();
}
inside the GetCurrentActiveTimeslot class
class GetCurrentActiveTimeSlotAction
{
public $test;
public function __construct()
{
$this->test = 5;
}
public function execute()
{
$value = $this->test;
return $value;
}
}
Yes, I did rename it to static function execute() but that broke another thing where now I get an error trying this
static function execute()
{
$value = $this->test;
return $value;
}
Alternatively, I tried this approach as well, ut now it says I need to pass a variable into the refreshTest function. Which I understand, but anything I pass in there seems to break it.
public function mount()
{
$this->refreshTest();
dd($this->timeSlot);
}
public function refreshTest(GetCurrentActiveTimeSlotAction $getCurrentActiveTimeSlotAction)
{
$this->timeSlot = $getCurrentActiveTimeSlotAction->execute();
}
Looking for any advice on how I can just do a calculation in the GetCurrentActiveTimeSlotAction and return the value inside the livewire component.
Assuming you don't want to do the trivial thing (e.g. $this->timeSlot = (new GetCurrentActiveTimeSlotAction)->execute();) and want to do dependency injection instead (because that will make your code more testable) then you can inject objects in your mount method (source):
use Livewire\Component;
use App\Actions\Broadcast\GetCurrentActiveTimeSlotAction;
class DisplayLiveBroadcastCard extends Component
{
public $timeSlot;
private $activeTimeslotActionGetter;
public function mount(GetCurrentActiveTimeSlotAction $getter)
{
$this->activeTimeslotActionGetter = $getter;
$this->refreshTest();
dd($this->timeSlot);
}
public function refreshTest()
{
$this->timeSlot = $this->activeTimeslotActionGetter->execute();
}
trait TestTrait
{
public function matches()
{
}
}
class TestClassOne
{
public static function matches()
{
}
}
class TestClassTwo extends TestClassOne
{
use TestTrait {
matches as alternativeMatches;
}
public function run()
{
$this->alternativeMatches();
}
}
When calling the method run as seen above it will return the error :Fatal error: Cannot make static method matches non static
The classes are not written by me and the trait I have used in multiple other locations. A hell if I have to rewrite the trait .. or have to make a new one , just to make it work with this class.
Is there a way to make it work ?
Cheers
Well I made it work with a bit of a hack ... but I do not like it...
Someone has a nicer way of doing this ?
class TestClassTwo extends TestClassOne
{
use TestTrait {
matches as alternativeMatches;
}
public function run()
{
$this->alternativeMatches();
}
public static function matches()
{
parent::matches();
}
}
For deleteBarDocument(), I wish not to implement
$this->getModel()->updateParentAudit($this->audit_table,$_POST['id']);
in the deleteDocumentHelper() helper method, but implement something else such as
$this->bla($_POST['id']);
$this->blabla($_POST['id'],$_POST['doc_id']);
How can I extend deleteDocumentHelper() for deleteBarDocument(), but leave it as is for deleteFooDocument()?
Normally, I would just replace
$this->getModel()->updateParentAudit($this->audit_table,$_POST['id']);
with
$this->doSomething();
and create a doSomething() method with whatever code is needed. The probably with this approach is it will affect both deleteFooDocument() and deleteBarDocument() which is not desired.
Or should I pass the helper method an anonymous function? I am cautious of doing so as I've been warned that anonymous function should be used sparingly.
<?php
class parentController
{
protected function deleteDocumentHelper($type){
if(isset($_POST['id'],$_POST['doc_id'])){
if(documents::removeDocument($type,$_POST['doc_id'],$_POST['id']))
{
$success=1;
//Ability to replace the following line with one or more lines
$this->getModel()->updateParentAudit($this->audit_table,$_POST['id']);
}
else {$success=0;}
header('Content-Type: application/json;');
$this->dontCache();
echo(json_encode(array('success'=>$success)));
}
else {exit($this->missingPage());}
}
}
class childController extends parentController
{
public function deleteFooDocument(){$this->deleteDocumentHelper('foo');}
public function deleteBarDocument(){$this->deleteDocumentHelper('bar');}
}
//Application creates childController object, and evokes apprpropriate method based on GET/POST
?>
You say:
Normally, I would just replace
$this->getModel()->updateParentAudit($this->audit_table,$_POST['id']);
with
$this->doSomething();
and create a doSomething() method with whatever code is needed. The probably with this approach is it will affect both deleteFooDocument() and deleteBarDocument() which is not desired.
But, why not in following way?
class parentController
{
protected function doSomething()
{
$this->getModel()->updateParentAudit($this->audit_table,$_POST['id']);
}
protected function deleteDocumentHelper($type){
if(isset($_POST['id'],$_POST['doc_id'])){
if(documents::removeDocument($type,$_POST['doc_id'],$_POST['id']))
{
$success=1;
//Ability to replace the following line with one or more lines
$this->doSomething();
}
(...)
}
else {exit($this->missingPage());}
}
}
class childController extends parentController
{
private $somethingElse = False;
protected function doSomething()
{
if( $this->somethingElse )
{
// Your deleteBar code
}
else
{
parent::doSomething();
}
}
protected function deleteDocumentHelper( $type, $somethingElse=False )
{
$this->somethingElse = $somethingElse;
parent::deleteDocumentHelper( $type );
}
public function deleteFooDocument(){$this->deleteDocumentHelper('foo');}
public function deleteBarDocument(){$this->$this->deleteDocumentHelper('bar',1);}
}
With this approach you can substantially leave untouched the parent class, and apply different code(s) only when needed.
Might be I am missing something obvious.
I have a native class with set and get method.
class DBStorage extends NativeClass{
public function get($key);
public function set($key,value);
}
I would like to use that most of the time, but, if I turn on the system DEBUG flag.
I would like the set and get methods to be overloaded with the following:
IF DEBUG IS ON{
class DBStorage extends NativeClass{
public function get($key){
var_dump($key);
parent::get($key);
}
public function set($key,$value){
var_dump($key,$value);
parent::set($key,$value);
}
}
}
NativeClass is written in C. It is an extension (phpredis, but it is not relevant).
How would I accomplish this?
I am on the 5.3 branch of PHP.
just to make sure...if debug is off, DBStorage will be:
class DBStorage extends NativeClass{}
if debug is on, it will be:
class DBStorage extends NativeClass{
public function get($key){
var_dump($key);
parent::get($key);
}
public function set($key,$value){
var_dump($key,$value);
parent::set($key,$value);
}
}
I do try to avoid the cluttring of IFs (there are dozens of functions in the real class)
public function get($key) {
if (DEBUG) {
var_dump($key);
}
return parent::get($key);
}
You can't conditionally overload, but you can conditionally do something in the overloaded method:
class DBStorage extends NativeClass{
public function get($key) {
if (DEBUG) {
var_dump($key);
}
return parent::get($key);
}
}
If debug is off, it passes the arguments right through to the parent method and returns the parent's return value, as if nothing happened.
Your initial code won't compile, because of the if around the class construct. Why not just make available a debug member variable, and if true, echo output, or push into a log file?
class NativeClass
{
public $debug = false;
}
class DBStorage extends NativeClass
{
public function get($key)
{
if (true === $this->debug) {
error_log(sprintf('Key: %s', $key));
}
parent::get($key);
}
}
// Calling code
$dbo = new DBStorage();
$dbo->debug = true;
$dbo->doStuff();
something just came to me
class nodebug extends NativeClass{
static public function create(){
if(DEBUG) return new DebugNativeClass;
return new self;
}
}
class DebugNativeClass extends nodebug{
public function set($key,$value){
var_dump($key,$value);
parent::set($key,$value);
}
public function get($key){
var_dump($key);
return parent::set($key);
}
}
I have an abstract page class looking like this:
abstract class Page {
public static function display() {
self::displayHeader();
self::displayContent();
self::displayFooter();
}
public static function displayContent() {
print "<p>some content</p>";
}
public static function displayHeader() {
include_once(kContent . "HeaderContent.class.php");
HeaderContent::display();
}
public static function displayFooter() {
include_once(kContent . "FooterContent.class.php");
FooterContent::display();
}
};
I would like to subclass from this, and only override the displayContent method, so the header and footer is being displayed automatically, but still having the option to override the display method, for example for .js files.
Now I have another class, looking like this:
class FooPage extends Page {
public static function displayContent() {
print "<p>Foo page</p>";
};
Now, instead of calling the FooPage's displayContent method, it just calls the one from the superclass.
Why? What can I do?
EDIT
I'm running PHP 5.2.17
Ilija, PHP < 5.3 doesn't have "Late Static Binding" and that's why you may be experiencing the FooPage::displayContent not being called. If you are running PHP 5.2 then there is nothing much to do (except for some hacks using debug_backtrace(), which honestly I wouldn't recommend for this situation).
Now, what it really calls my attention is that your methods are all static; is there a reason for this? Why aren't they instance methods? I would expect something like:
include_once(kContent . "HeaderContent.class.php");
include_once(kContent . "HeaderContent.class.php");
abstract class Page
{
protected $header;
protected $footer;
public function __construct()
{
$this->header = new HeaderContent();
$this->footer = new FooterContent();
}
public function display()
{
$this->displayHeader();
$this->displayContent();
$this->displayFooter();
}
public function displayContent()
{
print "<p>some content</p>";
}
public function displayHeader()
{
$this->header->display();
}
public function displayFooter()
{
$this->footer->display();
}
};
class FooPage extends Page
{
public function displayContent()
{
print "<p>Foo page</p>";
}
}
and later in your view you would write something like:
$page = new FooPage();
$page->display();
Some things to take into account:
It is generally better not to use print/echo when generating a view content. Instead try to create the string and do the print/echo as a last step. This makes it easier to later write tests.
Example:
public function display()
{
return
$this->displayHeader() .
$this->displayContent() .
$this->displayFooter();
}
public function displayContent()
{
return "<p>some content</p>";
}
public function displayHeader()
{
return $this->header->display();
}
....
$page = new FooPage();
echo $page->display();
If you need to do it as your application grows, you can pass the header and footer as Page constructor parameters. As long as they are objects that understand the display() message (i.e. polymorphic) things should be ok.
HTH
Returned back to this question. Was looking for solution for Symfony (5.4).
And I finally came with this "Service - method call" solution.
#services_dev.yaml:
Company\Core\PinGenerator\PinGenerator:
calls:
- [setDebugMode, [true]]
#PinGenerator:
class PinGenerator implements PinGeneratorInterface
{
public static bool $inDebugMode = false;
public static function setDebugMode(bool $inDebugMode): void
{
self::$inDebugMode = $inDebugMode;
}
public static function generate(int $length = self::DEFAULT_PIN_CODE_LENGTH, bool $numbersOnly = true): string
{
if (!self::$inDebugMode) {
return PinGeneratorProd::generate($length, $numbersOnly);
} else {
return PinGeneratorDev::generate($length, $numbersOnly);
}
}
}
Honesly hoping, that this will help someone, someday.