I am trying to use a interface or child class to work in a situation where I am using class hints on a method argument and keep getting the following warning:
$print_r(class_parents($listing));
$propertyTable -> getPhotos($listing);
Array ( [Tools\Object\Property] => Tools\Object\Property )
Catchable fatal error: Argument 1 passed to Tools\Db\PhotoTable::getPhotos() must be an
instance of Tools\Db\Property, instance of Tools\Object\Listing given, called in ...
and defined in ...
This is strange as you can see when tested listing extends property (see below). Why would I get this error?
I have set up a very basic test case and have figured out that type hints should accept a child class or a class that implements the required class where that class is an interface. However, in a name spaced Zend Framework 2 environment I cannot get this to work.
My code for the various classes looks like this:
namespace Tools\Db;
class PhotoTable
{
public function getPhotos(Property $propertyObject )
{
//code goes here
}
}
namespace Tools\Object;
use Tools\Object\PhotoInterface as PhotoInterface;
class property //implements photoInterface
{
public function getUrl(){ code goes here}
public function getPhotos(){ code goes here}
}//end class
use Tools\Object\PhotoInterface as PhotoInterface;
class Listing extends Property implements PhotoInterface
{
//code goes here
}
namespace Tools\Object;
interface PhotoInterface
{
public function getUrl();
public function getPhotos();
}
I can get the code above to work if I copy this all into a single file and eliminate the namespaces. Basically:
if I require property in PhotoTable I can pass Listing as it extends property.
If I require PhotoInterface I can pass Listing as it implements this interface.
But I get this weird error when I have essentially the same classes in a different files in a name spaced Zend Framework 2 environment.
Is there an extra complication in a name spaced environment I need to take into account of or am I missing something really basic.
It appears that the issue involved the name-spaced files included in the head of the script. Specifically, it appears you need to include not only the class being am passed, but also the specified parent classes or any Interface classes if they are specified in the type hint.
To give an example if my class type hint suggests I need 'property' class, then if I am sending it the 'Listing' object, it seems I need to include property in the header like this:
namespace Tools\Object;
use Tools\Object\Property; //the parent class
use Tools\Object\Listing; //the child class
This eliminates the fatal error, but it seems strange that PHP cannot automatically determine the class automatically. I assume it is something to do with the complexities of a name spaced environment.
Related
I'm trying to trick PHP into taking a class from another namespace when trying to create a specific class.
I have two class called "page", the first is in the Core namespace:
namespace Core;
class Page {...}
The second inherits from Core\Page, but adds a few things. It is in the Addons namespace.
namespace Addons;
class Page extends \Core\Page{...}
The reason I want to do this is because I want to build my system with an easy addon engine. Whenever I want, I can add a line in an XML file that tells the autoloading function to take the class in the addon namespace instead of the core namespace.
However, when I try to do this :
spl_autoload_register('loadClass');
public function loadClass(string $className)
{
if (Addon_exist_and_is_registered($className))
{
require "/Addons/$className.php";
}
else
{
require "/Core/$className.php";
}
}
$page = new \Core\Page(); <-- error here
I get an error saying that the class \Core\Page cannot be found in the file Addons\Page.php. This is normal behaviour since the class is not in the same namespace and as such, the fully qualified name cannot find the right class.
Is it possible to trick PHP into thinking that a child class in another namespace is actually the right class? I tried this for the addons class;
namespace Core;
class Page extends \Core\Page{...}
But it breaks the inheritance as you cannot inherit yourself.
Ignore that the classes have the "same name". Because they don't. One class is called Core\Page, the other is called Addons\Page. Those are their names, their fully qualified names to be exact. It's as much a difference as Foo and Bar. If you tell PHP to instantiate Core\Page, then it's going to do that; you can't "trick" it into instantiating Addons\Page, since that's an entirely different class name.
Don't try to "trick" anyone, make your system actually extensible and explicitly allow overriding of class names:
$class = 'Core\Page';
if (...) {
$class = 'Addons\Page';
}
$page = new $class;
I've been trying to build a PDO extension, and I wanted to have special classes in different files but I wanted to have them all link to the same original class.
I have worked with some Frameworks and I see that they use the extends class keyword, and I thought that it added the class you are making to the class that you have given.
Some code I have tried is:
class PSMQuery extends PSM {
// Functions and Jargon
}
I tried making an object for the original PSM class:
$psm = new PSM(/*Information*/);
But when I call the $psm variable like $psm->functionInTheExtendedClass it comes up with an error saying that it was an undefined method when I called it.
Am I using the extends keyword incorrectly?
Am I using the extends keyword incorrectly?
You use it correctly, but it works the other way around.
If PSMQuery extends from PSM, this means you can access and use stuff from PSM in PSMQuery, but not the other way around.
I think to understand it you can use a good example:
class twoRoomApartment extends building { }
So now you can think logical and already see, that a two room apartment probably extends from a building and not the other way around.
Means now in your code, you just create an instance of PSMQuery.
It's inheritance.
Parent : PSM
Child : PSMQuery
When you use extends you are extending parent class functionality and creating child class.
Your child class will inherit all the parent class functionality.
Parent will not get child class functionality.
So when u r trying to create object of parent class it doesn't know child class functionality.
You need to create object of child class and then you can access methods from parent class.
I call a CodeIgniter controller method -imgupload- from jquery ajax. This controller extends my custom front controller.
class newad extends My_Controller{
public function __construct() {
parent::__construct();
}
public function imageupload() {
$this->load->library("uploadhandler");
}
The imgupload method calls the uploadhandler class which extends from newad.
class uploadhandler extends newad {
The functionality of that class works properly, except for one thing, I cant access the properties of the My_Controller class, even though they are declared protected.
The inheritance chain looks like this: My_Controller->newad->uploadhandler.
Any idea why I cant access those properties?
In short the answer is you do not need to extend Controller class here. You can just pass the value to your library as a parameter.
$params = array('user_ud' => $this->userID, 'otehr' => 'other');
$this->load->library('uploadhandler', $params);
//Now from your library
class uploadhandler{
public function __construct($params)
{
// Do something with $params
}
//.. Your code...//
}
Now about your question:
The functionality of that class works properly, except for one thing, I cant access the properties of the My_Controller class, even though they are declared protected. The inheritance chain looks like this: My_Controller->newad->uploadhandler. Any idea why I cant access those properties?
As inheritance chain are ok, you can access property of My_Controller from your library but not the value of the Current controller, because these two are different object.
So here is my answer how can we access the value? One way I have already mentioned. That will be enough if you need to share some property with the library. But what if you need to access all the Controller instance. There is a function to get the reference of controller instance get_instance(). You can use this function anywhere and get access of all public property controller. If you need to access any private property of controller the define a geter function to access that.
Explanation
First of all you need to learn basic about OOP. Learn about Class, Object, Inheritance..
When I said property of My_controller is different from the same property the you accessed from uploadhandler, it may confused you if you are not familiar with class and object. Here is two instance(object) of different class.
For short let say you have some classes like: Vehicle, Car, Machine and Person. All they have common attributes say name, weight ..
So, can we just inherit Any of these class from other??
Simple answer is no. We can't(!) define a Person class extending from Others. So how can we decide which incoherence would legal. If you can say Foo is a Bar you can write Foo class extending from Bar. Now from your case, It is obvious uploadhandler is not a controller. So Never Extend a anything from something that is not something.
NB: The answer is generic. If you need any specific clarification, just ask, I can update my answer
I am creating a reporting library in PHP and developed an abstract class named ReportView. This will provide the basic functionality of a report like Generating header and footer, create parameter form.
There will be another function named generate_report in this class. Currently it is empty in abstract class as at this level we do not know the contents of report. Further it includes a render function which calls this generate_report function and sends output to browser.
So I need whenever a child class inherits from ReportView it must implement
the generate_report method otherwise PHP must give error. Is there any keyword or method through which we can enforce implemetation of a specific function.
Do the following:
abstract class ReportView {
abstract protected function generate_report();
// snip ...
}
class Report extends ReportView {
protected function generate_report() { /* snip */ }
}
Any class that extends ReportView and is not abstract must implement generate_report (and any other abstract function in its super classes for that matter).
Sounds like you’d be better off creating an interface, which would enforce you to define those methods in classes that then implement this interface.
<?php
interface ReportInterface {
public function generate();
}
class MyReportClass implements ReportInterface {
}
Instantiating MyReportClass here will throw a fatal error, telling you generate() has not been implemented.
Edit: You can also create abstract classes that implement this interface. You can have your abstract class contain any methods all extending classes need, and have your interface define any methods you need to be defined by extending classes.
You need to declare the method as abstract as well (and don't give it a method body), otherwise the derived classes will not be forced to implement it.
Alternatively, you could implement the method but have it just throw an Exception (not sure why you would want to do this).
Lastly, if all the methods in your base class are "abstract" (do not have bodies) then you can make the class into an Interface instead.
Szenario
I got a class as extend of an abstract class. The abstract class loads my files & extensions with their methods (link to pastebin for abstract class).
This gets called in my extends class like this (shortened & simplified - typos are only here at the Q-code):
class Pagination extends Pagination_Base
{
function __construct()
{
// loads the file "first.class.php" in the abstract class
parent::load_file( 'first' );
// stores the class as object in the abstract class, so we can access the methods and properties
parent::load_extension( new oxoFirst() );
}
}
Problem/Question
Now i got the error "Cannot redeclare class {$classname}".
I want to use my abstract class but still be able to move classes that contain extensions into separate files. Is there any way to do this?
Thanks in advance!
Use include_once instead of include in the load_file function.