First time extending a class in PHP and I'm getting a fatal error that says the method is private when it's not. I'm sure it's something elementary, but I've studied books and forums, and I just can't pin down what I've done to generate this error. Any help greatly appreciated. Details below:
Error message:
Fatal error: Call to private method testgiver::dbConnect() from context 'testprinter' in /root/includes/classes/testprinter.php on line 726
Line 726 of testprinter in the code below:
private function buildquestionarray()
{
$query = "etc etc";
**$conn = $this->dbConnect('read');
$result = $conn->query($query);
...
Testprinter extends testgiver. Here's the extension of the class:
require_once('testgiver.php');
class testprinter extends testgiver
{...
And the declaration of the method in testgiver:
protected function dbConnect($userconnecttype)
{...
Thanks again!
As already Alexander Larikov said that you can't access protected methods from class instance but not only protected methods but also you can't access private methods from class instance. To access a protected method of a parent class from the instance of a subclass you declare a public method in the subclass and then call the protected method of the parent class from the public method of the subclass, i.e.
class testgiver{
protected function dbConnect($userconnecttype)
{
echo "dbConnect called with the argument ".$userconnecttype ."!";
}
}
class testprinter extends testgiver
{
public function buildquestionarray() // public instead of private so you can call it from the class instance
{
$this->dbConnect('read');
}
}
$tp=new testprinter();
$tp->buildquestionarray(); // output: dbConnect called with the argument read!
DEMO.
You can't access protected methods from class instance. Read documentation which says Members declared protected can be accessed only within the class itself and by inherited and parent classes
The Alpha, great write-up!
I feel like I've almost got it where I want it, but am getting
Fatal Error, call to undefined method NameofClass::myFunction() in line 123456
Is there something I am missing here?
My original class, and the extending class are both in the same .php file, but the call to myFunction is happening in a different file. Is that not allowed?
NOTE: I would put this in a comment, but the system won't let me include comments until I have a reputation of 50.
Related
I do not understand this particular case or what Alexander says.
class instance is not the same as class?
As already Alexander Larikov said that you can't access protected
methods from class instance but not only protected methods but also
you can't access private methods from class instance. To access a
protected method of a parent class from the instance of a subclass you
declare a public method in the subclass and then call the protected
method of the parent class from the public method of the subclass,
i.e.
ALEXANDERS'S SOLUTION:
class testgiver{
protected function dbConnect($userconnecttype)
{
echo "dbConnect called with the argument ".$userconnecttype ."!";
}
}
class testprinter extends testgiver
{
// WHAAAAAT? WHYYYYY?
public function buildquestionarray() // public instead of private so you can call it from the class instance
{
$this->dbConnect('read');
}
}
$tp=new testprinter();
$tp->buildquestionarray(); // output: dbConnect called with the argument read!
'Fatal error call to private method' but method is protected
why can't I access a protected method from a private method if the protected ones are inherited by the subclasses?
CODE BEFORE SOLUTION:
Line 726 of testprinter in the code below:
private function buildquestionarray()
{
$query = "etc etc";
**$conn = $this->dbConnect('read');
$result = $conn->query($query);
...
Testprinter extends testgiver. Here's the extension of the class:
require_once('testgiver.php');
class testprinter extends testgiver
{...
And the declaration of the method in testgiver:
protected function dbConnect($userconnecttype)
{...
They didn't really explain it clearly in the other answers.
Visibility of properties and methods (which I'll refer to collectively as "names") is controlled by where the code that tries to access the name is running. It can be in top-level code, a regular function, or a class method. If it's in a method, what matters is the class where the method is defined.
It's not based on the class of the instance that the name is accessed through.
If the name is declared private, you can only use the name in a method of the class that declares the name.
If the name is declared protected, you can refer to it in a method of that class, and also a method of a parent or descendant class.
If the name is declared public (the default, which also applies if the property is added dynamically), you can refer to it from anywhere.
Lets say we have class B which extends class A. When creating new instance of class B and providing value into it that value is used in constructor of class A. Please check sample below.
I'm little bit confused about such behavior. If method "display" do not pass value into class A it should not get there, or am i missing something?
class A {
protected $changeableString = 'initial value';
public function __construct($providedText)
{
$this->changeableString = $providedText;
}
public function printString(){
echo $this->changeableString;
}
}
class B extends A {
public function display(){
echo $this->changeableString;
}
}
$test = new B('provided value');
$test->display();
edit: I have changed function __construct from protected to public according comments. It is indeed gives error, so if someone will review this issue now code is correct.
First of all the topic you are talking about is called Inheritance in Object-Oriented Programming (OOP).
If class B has no construct (__construct) then PHP will call the construct of class A.
And about display function, think of it as an addition to everything in class A but will not be available in class A
So class B is like class A but has one more function called display.
Note:
As #Brian said, if you try to call new B('provided value') that will produce the following error:
Fatal error: Uncaught Error: Call to protected A::__construct() from global scope in ..
and to solve it just make the construct of class A public so class B.
I have a quite strange issue and I don't know if this is due to call_user_func_array or not.
Testing on PHP 5.4
Current setup
I have, for example, an AuthController class that extends a base controller named Controller:
class AuthController extends Controller
{
public function login() {
return Response::json(array('error' => false, 'message' => 'I\'m in AuthController#login'));
}
}
In the extended Controller class, I have a constructor that sets up, for example, a database connection (I have a var_dump + exit added for testing purposes):
class Controller
{
protected $db;
protected function __construct() {
$database = Config::env('database');
var_dump($database);
exit;
}
}
Now to call the AuthController, I'm using call_user_func_array
call_user_func_array(array($controller, $route['action']), $data);
Now what should have happened:
What should have happened is that Controller's constructor should have fired, produced a dump on screen and exited the execution.
Instead:
Instead I'm actually getting the response from AuthController's login method Response::json().
The Controller's constructor never gets fired.
I am having a difficult time understanding why it doesn't work since the PHP manual states that constructors get fired on every new object instance and if a parent class has a constructor and the child class doesn't overwrite it, the parent class constructor is called automatically.
Does call_user_func_array not fire parent class constructors autmatically or have I misunderstood something about PHP constructor entirely?
I'll take a stab in the dark here, and say that you're actually doing this:
call_user_func_array(array('AuthController', 'login'), $data);
In other words, you're not passing an instance to call_user_func, you're just passing the string 'AuthController'. That means your method will get called statically. If you had error reporting and/or strict error reporting enabled, you should see a notice warning you about calling non-static methods statically.
The problem is (probably) that you're never actually instantiating your class, so no constructor is ever run. call_user_func won't instantiate it for you. You'll need to do that yourself:
call_user_func_array(array(new $controller, $route['action']), $data);
// ^^^
As PHP Document at http://php.net/manual/en/language.oop5.decon.php
PHP 5 allows developers to declare constructor methods for classes. 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.
Note: Parent constructors are not called implicitly if the child class defines a constructor. In order to run a parent constructor, a call to parent::__construct() within the child constructor is required. If the child does not define a constructor then it may be inherited from the parent class just like a normal class method (if it was not declared as private).
Example #1 using new unified constructors
<?php
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
}
// In BaseClass constructor
$obj = new BaseClass();
// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass();
// In BaseClass constructor
$obj = new OtherSubClass();
?>
Hope this will explain you about use of parent class constructor in child class.
also you can refere http://php.net/manual/en/function.call-user-func-array.php , here they mentioned how to call parent class function in call_user_func_array.
Example:
call_user_func_array(array($this, 'parent::__construct'), $args);
Edit 1
See below example:
class BaseClass {
protected function __construct() {
print "In BaseClass constructor<br />";
}
}
//class SubClass extends BaseClass {
// function __construct() {
// parent::__construct();
// print "In SubClass constructor<br />";
// }
//}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
function test(){
echo 'in test';
}
}
call_user_func_array(array('OtherSubClass', 'test'), array()); //
// In BaseClass constructor
$obj = new OtherSubClass(); //produce fatel error
output:
Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method OtherSubClass::test() should not be called statically in /var/www/html/test/test1.php on line 22
in test
Fatal error: Call to protected BaseClass::__construct() from invalid context in /var/www/html/test/test1.php on line 24
So if string give in call_user_func_array function then it is producing out put but with strict standard error, and while creating new object of the class producing fatal error.
Remember that the constructor is a special method called when a new object is created. call_user_func_array() does not call any constructor because it doesn't create any new object.
call_user_func_array(array($controller, $route['action']), $data);
From your question I assume $controller is an object of type AuthController. It is already created at the moment when you pass it to call_user_func_array(). It's constructor was called when the object was created.
But wait a minute? What constructor? The class AuthController doesn't define any constructor. It inherits the parent class constructor that is protected. Because it is not public it cannot be called and the object is not created; the script throws a fatal error and exits.
You can either change the visibility of Controller::__construct() to public (this way both classes can be instantiated and the constructor of Controller runs for both). Or, if you want to keep class Controller not instantiable for some reason you define a public constructor for class AuthController that calls the protected constructor of class Controller to do the job:
class AuthController extends Controller
{
public function __construct()
{
parent::__construct();
}
// other methods here...
}
I'm Trying to access an object in a class extended from another class. But I'm getting the error "Trying to get property of non-object".
This is the code: http://3v4l.org/ZLTWf#v500
why can i not access the $doo->var_2->var? i works fine with $foo->var_2->var (as it should) but why do i get an error when i extend the class? Is it allowed in PHP? Is there some extra code that will allow me to do that?
I'm even getting an "Undefined variable" error on $doo->$var_3
Problem is here
class TheClass extends SecondClass{
public $var_3;
function __construct(){
$this->var_3 = "Some Text...";
}
}
You have overwritten the parent constructor so when you instantiate the class the constructor of its parent will not be called since its overwritten.
You can fix it as
class TheClass extends SecondClass{
public $var_3;
function __construct(){
parent::__construct();
$this->var_3 = "Some Text...";
}
}
I am having some trouble with Symfony2. Namely in how to use the __construct() function. the Official Documentation is shockingly bad!
I want to be able to use the following:
public function __construct()
{
parent::__construct();
$user = $this->get('security.context')->getToken()->getUser();
}
How ever I get the following error:
Fatal error: Cannot call constructor in /Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php on line 11
Line 11 is "parent::__construct();"
I removed it and got the following, new error
Fatal error: Call to a member function get() on a non-object in /Sites/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php on line 242
I think I might need to set up the ContainerInterface DIC, but I have no idea how to do this (I tried and failed, miserably)
Any ideas folks?
Update - Tried changing to extend ContainerAware and got this error:
Fatal error: Class DEMO\DemoBundle\Controller\Frontend\HomeController cannot extend from interface Symfony\Component\DependencyInjection\ContainerAwareInterface in /Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php on line 43
Using the following code in the controller:
<?php
namespace DEMO\DemoBundle\Controller\Frontend;
use Symfony\Component\DependencyInjection\ContainerAware;
class HomeController extends ContainerAwareInterface
{
protected $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
I'm assuming you are extending the default Symfony controller? If so, a look at the code will reveal the answer:
namespace Symfony\Bundle\FrameworkBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAware;
class Controller extends ContainerAware
{
Notice that there is no Controller::__construct defined so using parent::__construct will not get you anywhere. If we look at ContainerAware:
namespace Symfony\Component\DependencyInjection;
class ContainerAware implements ContainerAwareInterface
{
protected $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
}
Again, no constructor and the container is not available until setContainer is called. So override setContainer and put your logic there. Or else just make a stand alone controller that does not extend the base controller class and inject your dependencies directly into the constructor.
Update Aug 2017
Still getting a few hits on this. If you really want to execute something before each controller then use a kernel controller listener. If all you need is the user then of course use getUser(). And please don't override setContainer(). In some cases it would work but it would just convolute your code.
I also frequently want an instance of the current User in most of my controllers. I find it is easiest to just do something like this:
class SomeController extends Controller
{
protected $user;
public function getUser()
{
if ($this->user === null) {
$this->user = $this->get('security.context')->getToken()->getUser();
}
return $this->user;
}
}
However, this is an overly simplistic example case. If you want to do more work before a Controller action is started, I suggest you define your Controller as a Service.
Also take a look at this article: Moving Away from the Base Controller
I have to retrieve the 'facade' manager for my rest api's resource. Not using the constructor and using a private function seems the easiest and simplest for me.
/**
* Class ExchangesController
* #RouteResource("Exchange")
*/
class ExchangesController extends Controller
{
/**
* Get exchange manager
* #return ExchangeManager
*/
protected function getExchangeManager()
{
return $this->get('exchange_manager');
}
/**
* #ApiDoc(
* description="Retrieve all exchanges",
* statusCodes={
* 200="Successful"
* }
* )
*/
public function cgetAction()
{
return $this->getExchangeManager()->findAll();
}
PS It's ok for me to use private/protected functions in my controller as long as it contains zero conditionals
You cannot call getUser() or get() for services in controller constructors. If you remember that, you will save lots of debugging time.
I know the question is very old, but I didn't found an answer until now. So I'll share it.
The goal here, is to execute a code everytime a action in our controller is called.
The __construct method doesn't work, because it's called before anything else, so you can't access the service container.
The trick is to overload each method automatically when they are called :
<?php
namespace AppBundle\DefaultController;
class DefaultController extends Controller {
private function method1Action() {
return $this->render('method1.html.twig');
}
private function method2Action() {
return $this->render('method2.html.twig');
}
public function __call($method, $args) {
$user = $this->get('security.tokenStorage')->getToken()->getUser();
// Do what you want with the User object or any service. This will be executed each time before one of those controller's actions are called.
return call_user_func_array(array($this, $method), $args);
}
}
Warning ! You have to define each method as a private method ! Or the __call magic method won't be called.
There are only two solutions to this problem:
Use a private method as pointed out by #Tjorriemorrie here. But this is a dirty method for purists. (I'm using this! :D );
Define the controller as a service, but this way you will lose all the shortcuts provided by Symfony\Bundle\FrameworkBundle\Controller\Controller. Here is the article that shows how to do this.
As told, personally, in my situation, I prefere a solution like this:
class MyController extends Controller
{
/** #var AwesomeDependency */
private $dependency;
public function anAction()
{
$result = $this->getDependency();
}
/**
* Returns your dependency.
*/
private function getDependency()
{
if (null === $this->dependency)
$this->dependency = $this->get('your.awesome.dependency');
return $this->dependency;
}
}
This is typically a class that I call MyManager where I put the code that I use in more than one action in the controller or that unusefully occupies lines (for example the code to create and populate forms, or other code to do heavy tasks or tasks that require a lot of code).
This way I mantain the code in the action clear in its purposes, without adding confusion.
Maybe the use of a property to store the dependency is an overoptimization, but... I like it :)
As i see, Controller extends ContainerAware, and if we take a look of ContainerAware it implements ContainerAwareInterface. So, ContainerAware must have declared the exact methods in it's interface. Add this line
public function __construct();
to the ContainerAwareInterface definition and it will be solved.