This question already has an answer here:
Too few arguments to function Db::__construct(), 0 passed in
(1 answer)
Closed 4 years ago.
When I run this, it complains that
Too few arguments to function Base::__construct(), 0 passed in [FileName].php on line 18 and exactly 1 expected
class Base {
protected $var;
public function __construct($var){
$this->var = $var;
}
}
class ChildA extends Base {
public function handle(){
echo $this->var;
}
}
$base = new Base(10);
(new ChildA())->handle();
But as you can see, I have passed:
$base = new Base(10);
Edit: As mentioned in answers and comments, the problem was not in here:
$base = new Base(10);
...but here:
(new ChildA())->handle();
What am I doing wrong? Also, what I am trying to achieve is that, there are many ChildX classes who need to extend Base and all these child classes must have the $var property. So, Instead of duplicating the $var in each child classes, I wanted to reduce typing effort by putting it in a parent class. But apparently, my plan didn't work out.
Your problem is actually this line:
(new ChildA())->handle();
Do this instead:
$child = new ChildA(10);
$child->handle();
You don't need to instantiate the base class separately.
One other thing. When both parent and child classes have a constructor, you can put parent::__construct($whatever); in the child's constructor to run the parent code also.
This is a simple concept of class instantiation, I think which you are getting it wrong.
When you did
$base = new Base(10);
you are creating an instance of the Base class only.
However, the following statement invokes another instance of the Child class. Note, the base variable and this child instance are two different entities, hence their behaviour will not impact each other.
(new ChildA())->handle();
So, currently base variable will have a value of 10, but the handle() function call cannot be instantiated since it requires an argument which is to be supplied to the new instance of the Base class.
You'll need to instantiate the child class, due to which the constructor of the inherited class will be called first and your variable will be set. Your handle() function can then successfully return the correct value.
$child = new Child(10); $child->handle(); //returns 10
When you extend a class, all the methods on that class exist on the child class by default, including "magic" methods like __construct.
So when you write this:
class Base {
protected $var;
public function __construct($var){
$this->var = $var;
}
}
class ChildA extends Base {
public function handle(){
echo $this->var;
}
}
Your child class actually looks something like this:
class ChildA extends Base {
// Inherited property from Base class
protected $var;
// Inherited method from Base class
public function __construct($var){
$this->var = $var;
}
// New method in this class
public function handle(){
echo $this->var;
}
}
This is a slight simplification, as we'll see below, but it explains what happens in your example:
$base = new Base(10);
$base is an instance of the Base class; it is completely separate from any other instance of that class, and from any instance of the ChildA class.
(new ChildA())->handle();
This attempts to run the __construct method in the ChildA class; the copy of that method inherited from Base requires an argument, but you didn't supply one, so you get an error. It is expecting you to call it like this:
(new ChildA(10))->handle();
If we define __construct directly in the child class, we can give it a different number of arguments:
class ChildB extends Base {
public function __construct() {
// Do nothing
}
public function handle(){
echo $this->var;
}
}
(new ChildB())->handle();
But now we have a different problem: the logic in the Base class isn't running, so $this->var is never set to anything.
This is where I over-simplified things above. In reality, the parent __construct method and child __construct method both exist, they just "hide" each other. You can access the parent copy with the syntax parent::method.
So you can make a child class, with a constructor which takes no arguments, and when that constructor is run, run the base constructor with a hard-coded value of 10:
class ChildC extends Base {
public function __construct() {
// Run the constructor in the Base class
parent::__construct(10);
}
public function handle(){
echo $this->var;
}
}
(new ChildC())->handle();
Your new ChildA() is calling constructor from Base and you are not passing any arguments here.
You make mistake here: when you do new Base(10) your $var is not passed to new instance of new ChildA()
In your case I would use static parameter instead of constructor value
class Base {
protected static $var;
public function __construct(){
}
public static function setVar($var) {
self::$var = $var;
}
}
class ChildA extends Base {
public function handle(){
echo self::$var;
}
}
Base::setVar(10);
(new ChildA())->handle();
Related
I want to declare a non-public constructor so it's users of the class can't call new Message() directly but have to instantiate the object from a static builder method declared on an abstract class that Message extends.
So far my code is:
abstract class SqlDecodable {
public function instanceFromRawSql (array $rawSql) {
$newInstanceToReturn = new static() // problem is here
// .. map the new instance ..
return $newInstance ;
}
}
// for exemple...
class Message extends SqlDecodable {
private $receiverId ;
private $senderId ;
private $text ;
private/protected/public?? function __construct() {
// problem here : this constructor should be usable only by
parent class, not for user of Message
}
static function propertiesToSqlFields() {
return [
"receiverId" => "receiver_id_field_in_db",
"senderId" => "sender_id",
"text" => "text"
]
}
}
This is actually more complicated, but I simplified the system for this question
When I implement my method instanceFromRawSqlArray, I have to create a new instance of the child class: $instanceToReturn = new static(), and set the variables one by one afterwards.
Though, I don't want to let a __construct that takes no args in my model classes. I don't want the dev user of Message to be able to new Message().
This constructor should be usable only by instanceFromRawSqlArray.
The problem is that, as I saw, there is no C++ friends class in PHP. I can't make my __construct protected, because, as I saw, protected methods are accessibles for childs, not for parent.
Do you have ideas to map this new instance in the method instanceFromRawSqlArray, without creating any constructor or setter that would corrupt my model class "encapsulation protections"?
You were very close. You can simply declare your constructor to be protected.
Instantiating the class directly won't work, but you can call new from the static method declared in the abstract class.
E.g.:
abstract class SuperAbstract {
static function create() {
return new static();
}
}
class Extended extends SuperAbstract {
private $hello = '';
protected function __construct() {
$this->hello = "world";
}
public function hello() {
return "hello " . $this->hello;
}
}
// works
$a = Extended::create();
echo $a->hello(); // outputs "hello world"
// can't touch this. This will fail because the constructor is `protected`.
$b = new Extended();
Of course, since it's protected the constructor could also be called from children classes. That's unavoidable, as long as children classes are a possibility. But you could also declare Extended as final, making extension of the class impossible. Thus, it would only be possible to create new instances from the factory method defined in the abstract parent.
final Extended extends SuperAbstract
protected function __construct() { }
}
You can see it working (and failing), here: https://3v4l.org/LliKj
I have a code like following ---
class CartItem{
var $v;
function __construct(){
$this->f();
}
function f(){
echo 'In parent';
}
}
class m extends CartItem{
function f(){
echo 'In child';
}
}
new m();
Now when creating instance of m()... it doesn't have any constructor, so it is calling parent classes constructor. Now inside that a function f is called.
What I want is -
if class m() have defined function f()... is should call it instead of parent class's function f().
But anyway it is calling parent classes function, as it was called from parent's constructor, irrespective of child class/ context :(
You want to call in __construct() a method that is not defined in the class. This is a sign that the CartItem class is an abstract concept and you don't intend to instantiate it (because an instance of CartItem probably doesn't contain enough information or behaviour for your project).
An abstract concept is implemented using an abstract class that defines as much as it can and defines abstract methods to be implemented in the concrete classes that extend it. The method f() is such a method that cannot be defined in the abstract concept and has to be defined in each class that extend it:
abstract class CartItem
{
public function __construct()
{
$this->f();
}
abstract protected function f();
}
class m extends CartItem
{
protected function f()
{
// Implement behaviour specific to this class
}
}
This is actually a really interesting question.
so, as I understand it, you're asking (if this isnt right please say):
can you call a function of a class that's extending a parent?
yes, you can... sort of, if the method in the child is static.
Take this example (Ive not used it in the constructor for simplicity of example, but it will work there too):
class ClassA {
public function testMeAsWell() {
return ClassB::testMe();
}
}
class ClassB extends ClassA {
static function testMe() {
return 'do something';
}
}
$child = new ClassB();
echo $child->testMe();
// outputs 'do something'
$parent = new ClassA();
echo $parent->testMeAsWell();
// also outputs 'do something'
the reason this works needs more research, but as a guess I would say that because PHP is compiled, it will know about both classes at run-time and therefore will be able to figure out what we wanted it to do.
So, further on, you want to use variables. Yes you can, but they would have to be static as well.
working example
Looking for a clean way to determine the class (in this case, either parent or child class) of the method that calls a method in the parent class.
I thought late static binding could handle this, but seems like that only really works for calling a static method directly, and not from within an instantiated object's method.
Consider the following:
abstract class ParentClass {
public function parentMethod() {
self::_log("parent.non.static");
}
public static function parentStatic() {
self::_log("parent.static");
}
public static function getClassName() {
return __CLASS__;
}
protected static function _log($key) {
$prefix = 'graphite.key.prefix';
$class = static::getClassName(); // gets the object's class, not calling class
$g_key = "{$prefix}.{$class}.{$key}";
echo "{$g_key} \n";
// Graphite::increment($g_key);
}
}
class ChildClass extends ParentClass {
public function childMethod() {
self::_log("child.non.static");
}
public static function childStatic() {
self::_log("child.static");
}
public static function getClassName() {
return __CLASS__;
}
}
$obj = new ChildClass;
$obj->childMethod(); // graphite.key.prefix.ChildClass.child.non.static
$obj->parentMethod(); // graphite.key.prefix.ChildClass.parent.non.static
ParentClass::parentStatic(); // graphite.key.prefix.ParentClass.parent.static
ChildClass::childStatic(); // graphite.key.prefix.ChildClass.child.static
Looking for a clean way to get the class that calls the _log() method without having to pass it in as a parameter. Doesn't have to be static at all, but I was playing around with the late static binding, because I thought that would work, but it just gets the name of the instantiated object, not the child/parent class of the method that calls the _log() method :-/
Edit:
Just to be clear, I'm after getting the class name of the method that called _log() from within the instantiated object (like parentMethod() and childMethod()) Don't care if _log() is static or not. If that makes it easier, fine. But the static ParentClass::parentStatic() and ChildClass::childStatic() were just to show late static bindings and what I figured might work, but not from calling within an instantiated object
http://php.net/manual/en/function.get-called-class.php
class One {
public static function test() {
echo get_called_class() . PHP_EOL;
}
}
class Two extends One {}
One::test();
Two::test();
Output:
One
Two
Also, according to the top comment in the docs static::class also works as of PHP 5.5.
get_class will get the class name of a class instance. This can also be called on $this within a class. If you have a class that extends/implements another, $this will refer the the instantiated class, meaning the child class.
Another option is to use debug_backtrace to get the stack of functions that lead up to where you currently are. You can parse the returned array to get whatever you need including line numbers, classes, functions, methods, whatever.
Is there any difference in constructor or unified constructor. I have a class which have a constructor and a unified constructor. When i intialise object of the class then unified constructor call why not normal constructor.
<?php
class test {
function __construct() {
print "In BaseClass constructor\n";
}
function test() {
echo 'Class loeaded';
}
}
$obj = new test();
?>
OUTPUI
In BaseClass constructor
PHP Version 5.2.6
Since PHP 5, the best way to declare a constructor method in a class is to use the standardized
__construct()
So if you have
class myA {
public function __construct() {
echo "hello construct myA";
}
public function myA() {
echo "hello basic way myA";
}
}
$myA = new myA();
It will echo
hello construct myA
because the __constructor() has priority
But, for compatibility reason, the old way may work if there is not __construct() method.
And:
class myA {
//public function __construct() {
// echo "hello construct A";
//}
public function myA() {
echo "hello basic way myA";
}
}
$myA = new myA();
will give you:
hello basic way myA
In all cases, I advise you to use __construct()
the old constructor (method with class name) is only there for compatibility reasons. so if you have the new constructor (__construct) in the class php won't bother to call the old one.
edit
interesting note is that calling parent::__construct when the class being extended has only the old constructor type will still work (it becomes like a alias to the real constructor)
Classes which have a constructor method call this method on each newly-created object, so it is suitable for any initialization that the object may need before it is used.
Read documentation of constructor (link)
Instances of classes are created using the new keyword. What happens during the new call is that a new object is allocated with its own copies of the properties defined in the class you requested, and then the constructor of the object is called in case one was defined. The constructor is a method named __construct(), which is automatically called by the new keyword after creating the object. It is usually used to automatically perform various initializations such as property initializations. Constructors can also accept arguments, in which case, when the new statement is written, you also need to send the constructor the function parameters in between the parentheses.
In PHP 4, instead of using __construct() as the constructor’s name, you had to define a method with the classes’ names, like C++. This still works with PHP 5, but you should use the new unified constructor naming convention for new applications.
We could pass the names of the people on the new line in the following class example :
class Person {
function __construct($name)
{
$this->name = $name;
}
function getName()
{
return $this->name;
}
private $name;
};
$judy = new Person("Judy") . "\n";
$joe = new Person("Joe") . "\n";
print $judy->getName();
print $joe->getName();
Tip: Because a constructor cannot return a value, the most common practice for raising an error from within the constructor is by throwing an exception.
According to documentation As of PHP 5.3.3, methods with the same name as that of class will no longer be treated as constructor .. They are like regular methods ...
<?php
class myclass
{
public function myclass()
{
// treated as constructor in PHP 5.3.0-5.3.2
// treated as regular method as of PHP 5.3.3
}
}
?>
`
For backwards compatibility, if PHP 5 cannot find a __construct() function for a given class, and the class did not inherit one from a parent class, it will search for the old-style constructor function, by the name of the class.
It means that there if you have constructor myclass() and __construct .. then __construct will be searched for first and taken as constructor instead of myclass()
class myclass
{
public function myclass()
{
echo 'hello';
}
function __construct() {
print "new constructor"
}
}
$obj = new myclass(); // will echo new constructor
i have the following classes.
class base {
private function __construct(){
//check if foo method exists
//$this->foo(); // if it exists
}
public static function singleton(){
if(!isset(self::$singleton)){
self::$singleton = new base();
}
return self::$singleton;
}
}
class sub extends base{
public function __construct() {
parent::singleton();
}
public function foo(){
}
}
then init it like so
$test = new sub();
my problem is that I want to check on base __construct if the sub has a foo method.
but it doesn't seem to have this method.
can someone tell me where have I gone wrong?
Although you call parent::singleton() from sub class, but the singleton() still creates you instance of base class (because you do new base()), which does not have your foo() method.
In general you shouldn't use/call any methods from base class, which aren't define in it. Because it makes your code not clean: what if you will implement some another class which extends your base class, but forgets to implement the foo() method? You can end up with fatal errors quite fast...
If you are sure, that this foo() method will be always implemented by any child class - you can define in as abstract method in base class - then any child class will be forced to implement it. Or at least as an empty method in the same base class... This way your code will be clean and structured.
The method foo will not exist as the singleton being creating is an instance of base. Here's what's happening:
Create an instance of sub
Constructor of sub gets the singleton instance.
singleton() creates an instance of base
base constructor checks if the base class contains a method named foo. It does not.
Edit
i got a url e.g. site.com/sub/foo so the class sub is called and i want the base to check if foo does not exist then i will break the code... foo can be anything as long as it exists as a method on sub class
In this case the singleton pattern is superfluous. Instead, you can start with a basic factory class that implements the desired front controller pattern:
class factory {
static public function go($path) {
list($type, $action) = explode('/', $path);
if (class_exists($type) && // Does the requested type/class exist?
is_subclass_of($type, 'factory') && // Basic security. Make sure URL requests can't create an instance of *any* PHP class
method_exists($type, $action)) // Check requested method/action
{
$o = new $type;
$o->$action();
}
}
}
class sub extends factory {
public function foo() {
echo('To foo or not to foo that is the question.');
}
}
factory::go('sub/foo');