Why Can't I Overload Constructors in PHP

Why can't I overload constructors in PHP?

You can't overload ANY method in PHP. If you want to be able to instantiate a PHP object while passing several different combinations of parameters, use the factory pattern with a private constructor.

For example:

public MyClass {
private function __construct() {
...
}

public static function makeNewWithParameterA($paramA) {
$obj = new MyClass();
// other initialization
return $obj;
}

public static function makeNewWithParametersBandC($paramB, $paramC) {
$obj = new MyClass();
// other initialization
return $obj;
}
}

$myObject = MyClass::makeNewWithParameterA("foo");
$anotherObject = MyClass::makeNewWithParametersBandC("bar", 3);

Constructor Overloading in PHP

PHP doesn't have overloading. It has a series of magic methods that are described as overloading in the manual (see: http://php.net/manual/en/language.oop5.overloading.php), but it's not what you're thinking of.

Also, as an aside, the correct way to write a constructor in PHP 5+ is to use the __construct method:

public function __construct(/* args */)
{
// constructor code
}

Best way to do multiple constructors in PHP

I'd probably do something like this:

<?php

class Student
{
public function __construct() {
// allocate your stuff
}

public static function withID( $id ) {
$instance = new self();
$instance->loadByID( $id );
return $instance;
}

public static function withRow( array $row ) {
$instance = new self();
$instance->fill( $row );
return $instance;
}

protected function loadByID( $id ) {
// do query
$row = my_awesome_db_access_stuff( $id );
$this->fill( $row );
}

protected function fill( array $row ) {
// fill all properties from array
}
}

?>

Then if i want a Student where i know the ID:

$student = Student::withID( $id );

Or if i have an array of the db row:

$student = Student::withRow( $row );

Technically you're not building multiple constructors, just static helper methods, but you get to avoid a lot of spaghetti code in the constructor this way.

How to overload class constructor within traits in PHP = 5.4

I think for now the only way to do what you want is:

class MyHelloWorld extends Base {

use SayWorld {
SayWorld::__construct as private __swConstruct;
}

public function __construct($a, $b, $c = 0)
{
$this->__swConstruct($a, $b, $c);
}
}

Edit 2:

My advice, based on over a year of dealing with traits in PHP, is: avoid writing constructors in traits at all, or if you must - at least make them parameterless. Having them in traits goes against the idea of constructors in general, which is: constructors should be specific to a class to which they belong. Other, evolved high-level languages don't even support implicit constructor inheritance. This is because constructors have far more stronger relation to the class then other methods. In fact they have so strong relation, that even the LSP does not apply to them. The traits in Scala language (a very mature and SOLID-friendly successor of Java), can't have a constructor with parameters.

Edit 1:

There was a bug in PHP 5.4.11, which actually allowed to alias a superclass method. But this was considered a no-no by the PHP developers, so we are still stuck with that cumbersome solution which I presented above. But that bug raised a discussion about what can be done with this, and I'm hoping it will be targeted in future releases.

Meanwhile I came across the same problem over and over again. My irritation raised exponentially with the number of parameters and lines of docblock which had to be repeated a lot of times in order to use the trait. So I came up with the following pattern in order to stick to the DRY rule as much as I could:

Instead of repeating entire set of parameters like this:

trait SayWorld {

/**
* This is a valid docblock.
*
* @param int $a Doc comment.
* @param int $b Doc comment.
*/
public function __construct($a, $b) {
echo (int)$c * ($a+$b);
}
}

class MyHelloWorld extends Base {

use SayWorld {
SayWorld::__construct as private __swConstruct;
}

/**
* Repeated and unnecessary docblock.
*
* @param int $a Doc comment.
* @param int $b Doc comment.
* @param int $c Doc comment.
*/
public function __construct($a, $b, $c = 0)
{
$this->__swConstruct($a, $b);
}
}

I write a class much like a tuple (concept familiar to C# and Python users), and use it instead of an endless list of parameters:

class SayWorldConstructTuple
{
public $a;

public $b;

public function __construct($a, $b)
{
$this->a = $a;
$this->b = $b;
}
}

class MyHelloWorld extends Base {

use SayWorld {
SayWorld::__construct as private __swConstruct;
}

/**
* New and valid docblock.
*
* @param SayWorldConstructTuple $Tuple
* @param int $c Additional parameter.
*/
public function __construct(SayWorldConstructTuple $Tuple, $c = 0)
{
$this->__swConstruct($Tuple->a, $Tuple->b);
$this->c = $c;
}
}

Note: this pattern is of course more useful with a larger amount of tuple's constructor parameters, and more classes using the tuple.

It can be automated further with the use of PHP's dynamic nature.

oop PHP more than one constructors

  1. There are many ways of declaring 'multiple' constructors in PHP, but none of them are the 'correct' way of doing so (since PHP technically doesn't allow it). I don't see anything wrong with how you're doing it there, however. If you'd like more information, check out this Stack Overflow question.

  2. You could just use an if statement. Something like this, perhaps?

    public function __set($property_name,$value)
    {
    $hidden_properties = array(
    'comment_id',
    'any_other_properties'
    );

    if(!in_array($property_name, $hidden_properties) &&
    property_exists($this, $property_name))
    {
    $this->$property_name = $value;
    }
    }

Php overloading function issue with Class

1) Here the $clientPolicy variable that is passed to this function, needs be a ClientPolicy instance.

In this way, if the argument that is passed is different from an instance of ClientPolice class, an error is generated.

function SyncAPIClient(ClientPolicy $clientPolicy) {
$this->clientPolicy = $clientPolicy;
}

https://wiki.php.net/rfc/typed_properties_v2
https://laravel-news.com/php7-typed-properties

2) The error Cannot redeclare SyncAPIClient::SyncAPIClient() is caused because you are trying to declare two functions called SyncAPIClient ().

If in first SyncAPIClient() method you just want save the $clientPolicy in $this->clientPolicy, you can use the magic method __construct. Or just try changing the name of one of the functions, and the problem should be a problem.

class SyncAPIClient{

__construct(ClientPolicy $clientPolicy) {
$this->clientPolicy = $clientPolicy;
}

function SyncAPIClient($appKey, $appSecret) {
$this->clientPolicy = new ClientPolicy();
$this->clientPolicy->appKey=$appKey;
$this->clientPolicy->secKey=$appSecret;
}

}

https://www.php.net/manual/en/language.oop5.decon.php
http://www.zentut.com/php-tutorial/php-constructor-and-destructor/

Hope this helps!

Why PHP constructors don't return a usable object?

MyClass() could be a function call which returns an object whose doSomething method returns a string which refers to a class which you're then trying to instantiate with new, i.e.:

$className = MyClass()->doSomething();
new $className;

The added () are for syntactical disambiguation.

Why constructors can't return a value other than object even if it is explicitly instructed to do so?

A constructor is implicitly called when an object is created (with new). However, its return value is not used in that case, and has nothing to do with the object that is being created.

It is not the constructor that creates the object, because even without one, an object would be created anyway. What's more, when the constructor runs, the object is already there.

No return value is expected from a constructor. According to the manual it has no return type:

Constructor

void __construct ([ mixed $args = "" [, $... ]] )

You are of course free to return something and use that when you call that function explicitly, as with any other function, but don't expect that call to create another instantiation of your class. For that you need to use the new syntax.

The return value plays no role when it is called implicitly during object creation: the return value is ignored in that case.



Related Topics



Leave a reply



Submit