This should be a pretty straightforward classes and interfaces question, but please bear with me while I lay out my example.
In the Propel ORM library, all the database tables are abstracted as classes called BaseTablename. Various methods for interacting with the database are defined in the base obect. Then the library also generates classes named after the tables, such as Tablename, which are super convenient for overriding the base methods and adding custom methods.
I'm just trying to override the default delete() method to be able to delete some dependent data. But when I declare the overriding method, I get the following error:
Fatal error: Declaration of Tablename::delete() must be compatible with that of Persistent::delete()
So, considering the following basic definitions, why is it that I cannot override the delete() method?
/**
* Part of the Propel library
*/
interface Persistent {
public function delete (PropelPDO $con = null);
}
/**
* Generated by Propel
*/
class BaseTablename extends BaseObject implements Persistent {
public function delete (PropelPDO $con = null) {
doesImportantStuff();
}
}
/**
* Skeleton class is generated by Propel
*/
class Tablename extends BaseTablename {
/**
* MY OWN BEAUTIFUL [BUT BROKEN] CODE
*/
public function delete (PropelPDO $con = null) {
doMyOwnStuff();
// Added this 2011-05-30 -- As it happens, this IS the Problem!
// I needed to add the $con parameter to the call to preserve
// the "chain of compatibility", so to speak.
parent::delete();
}
}
Update: I've added my parent::delete() call, which I failed to include in my original example code. It really would have made all the difference. Sorry folks, and thanks so much to those who confirmed the working code
The answer was that I needed to preserve the parameter on all declarations and calls. My overloaded function should have read:
public function delete (PropelPDO $con = null) {
doMyOwnStuff();
parent::delete($con);
}
This code works. Problem must be in server copy or PHP version. (I've run the tests over PHP Version 5.3.3-7+squeeze1 without problems)
Well I've run another simple test. Using your code but with two echo's and it works as expeted. Like in C in this case the interface acts as a prototype so as you say, it's needed to be the same params and visibility on the classes that it implements.
Related
Recently I often see code like the following (this example is taken from Symfony):
protected function execute(InputInterface $input, OutputInterface $output)
{
throw new LogicException('You must override the execute() method in the concrete command class.');
}
What is the benefit here over just marking the method as abstract?
What's the benefit for the ...
... library author?
... library user?
I already found a similar question for Java (Faking abstract methods using exceptions in Java), but it wasn't very helpful as its answers are explicit guessings and opinions.
In this particular case, the comments explain:
/**
* Executes the current command.
*
* This method is not abstract because you can use this class
* as a concrete class. In this case, instead of defining the
* execute() method, you set the code to execute by passing
* a Closure to the setCode() method.
*
* #return int|null null or 0 if everything went fine, or an error code
*
* #throws LogicException When this abstract method is not implemented
*
* #see setCode()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
throw new LogicException('You must override the execute() method in the concrete command class.');
}
You could argue with the overall design as it is perhaps a bit hacky but it works well in practice. Take a look at Command::run to see where the decision to use a closure or execute is made. Bit of a niche case to say the least.
I know quite a bit of this was discussed in the comments of the other answer but I thought it might help to summarize. I also did a quick search through the Symfony framework code looking to see where the closure approach was used. Did not find anything. The closure support goes all the way back to the original 2.0 release so it might have one of those "seemed a good idea at the time" bits of functionality.
A possible use case is optional methods. If you make it abstract then all child classes need to implement it:
abstract class Database
{
abstract public function export();
}
class MySQL extends Database
{
}
Fatal error: Class MySQL contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Database::export)
If you make a regular method then child classes only need to implement the method if they plan to support it.
abstract class Database
{
public function export(){
throw new \LogicException(__CLASS__ . ' driver does not support ' . __FUNCTION__);
}
}
class MySQL extends Database
{
}
... yet you get a nice error if you attempt to use it:
$s = new MySQL();
$s->export();
Fatal error: Uncaught exception 'LogicException': MySQL driver does not support export
only abstract classes can have abstract methods.
You can't create object from abstract classes.
All abstract methods must be implemented in non-abstract classes.
Constructed Example:
Imagine the following:
abstract class Repository {
public abstract function read();
public abstract function write($object);
public abstract function delete($object);
public function connection() {
//this is implemented for you by the framework so you don't have to do it every time
}
Now you want to implement a repository for logging user-actions (logged-in, logged-out, ...)
You don't want any of those entries to be deleted and that's when you don't want to implement the delete function. But you have to, because your UserActionRepository is not abstract, because you actually need instances of it. that's when you throw an exception.
I have class, where i make connection to database and do some queries.
But i can't make query to this database from other class. Problem is that class Cd can't see db connection command -> can't make a query. Here is the code:
require_once('config.php');
class myClass
{
public $mysqli;
public $res;
function connect()
{
$database = new Database();
$this->mysqli = new mysqli($database->db_host, $database->db_user, $database->db_pass, $database->db_table);
}
function cd($id)
{
......
}
}
}
class Cd extends myClass
{
function cdname($id)
{
$get= new Scandiweb();
$get->mysqli;
$this->res = $get->mysqli->query("SELECT * FROM disk WHERE id=" . $id . "");
if ($this->res->num_rows > 0) {
.........
}
}
}
Your code is a bit messy, so it's hard to tell where exactly the problem lies:
Why do you require config?
Why do you create a Database (which is more like a DbConfig) in the constructor instead of passing it?
What is the Scandiweb-class?
Why do you call mysqli->query on that class instead of $this
The last one is your immediate mistake. You extend myClass which creates the mysqli-connection and stores it as class variable $this->mysqli. That means that the child class Cd will have access to it. When you extend a class you can call all it's public and protected properties and methods. Only those marked as private can't be accessed.
That means instead of accessing $get->mysqli->query(...) you can do $this->mysqli->query(...). What would make sense in OOP is to create a connection once (like you do in the constructor) and pass it around to the services requiring a database connection. This is called Dependency Inversion Principle and using a Dependency Container makes it easier (but is not mandatory).
There are so called design patterns that will make it easier to deal with performing sql queries like in your code above. The most common ones are the Active Record-pattern as used in Laravel's Eloquent and the Propel library, the Table Data Gateway-pattern as used in Zend Framework's DB-component and the Data Mapper-pattern as employed by Doctrine ORM. If you want to write OOP code you should look at their documentation and maybe use one of those instead of dealing with everything yourself.
I've been trying to learn CakePhp for a while now but I still can't get alot of stuff. I've been reading a lot and watching videos. I just want to ask a very simple question.
I've been trying to mess with the bookmarks tutorial and i'm watching a video. In the video he baked a component called Validate. In the cmd he typed
bin/cake/bake component Validate
Then a ValidateComponent.php appeared in the component folder in the controller. Now he used the ValidateComponent.php by going to the BookmarksController and adding to the initialize method
$this->loadComponent('Validate');
I just want to ask where did the word validate come from? shouldn't it be ValidateComponent? and where does he get the loadComponent from? I've seen him using $this->method(); or $this->method('string', [array]); I just want to know how the syntax works and what each word means. Sorry for the long explanation. I'm really trying to learn and i'm really confused. thank you very much.
ValidateComponent.php
<?php
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Controller\ComponentRegistry;
/**
* Validate component
*/
class ValidateComponent extends Component
{
/**
* Default configuration.
*
* #var array
*/
protected $_defaultConfig = [];
public function validLimit($limit, $ default)
{
if (is_numeric($limit)){
return $limit;
}
return $default;
}
}
part of BookmarksController.php
public function initialize()
{
parent::initialize();
$this->loadComponent('Validate');
}
I can't seem to find where he got the word 'Validate'
Every controller in your application extends a base Controller Controller or AppController which extends Controller
Controller have bunch of methods, One of these methods is the loadComponent() (See Source)
public function loadComponent($name, array $config = [])
{
list(, $prop) = pluginSplit($name);
$this->{$prop} = $this->components()->load($name, $config);
}
Why Validate instead of ValidateComponent?
Short answer: suffix.
See predefined suffix in App class
CakePHP uses suffix to load classes, When you hit loadComponent() You go to ComponentRegistery class to Register the component, ComponentRegistery will call App class to load class. __loadClass()
Almost everything in CakePHP has a suffix, In your case ValidateComponent has the Component suffix.
return App::className($class, 'Controller/Component', 'Component'); (Source)
I hope this will make more sense to you
$this isn't specifically anything to-do with cake but part of PHP itself. In object oriented context $this refers simply to the current class.
$this->something refers to an object within the current scope. This could be within the current class or from an extends or use.
$this->something(); refers similarly to a method or function within the current scope.
If are using an IDE such as netbeans you can usually click through these references to see the object they refer to so for example if you do in fact use Netbeans you could ctrl-click on $this->loadComponent('Validate'); to see the actual function it refers to.
Regarding where does 'Validate' come from, it's a string you are passing to that object. On the other end it will be used in the function, probably in a switch or if statement to return something.
Eg:
Public function loadComponent($type){
If($type == 'Validation'){
//do something
}
}
I am trying to develop an object oriented PHP application in which whole php application will be extending from MyApplicationBase base class. But the problems is I want to create only single instance of MyApplicationBase. Below is the code which explains what I mean
class MyApplicationBase{
static $called=0;
public var $db;
function __construct()
{
self::$called++;
echo "<pre>MyApplicationBase Created ".self::$called." times</pre>";
$this->db=new DatabaseWrapper();
}
}
class ApplicationSecurity extends MyApplicationBase{
function is_logged_in()
{
$res=$this->db->query("user check db query goes here");
return ($res)?true:false;
}
//..... other methods related to ApplicationSecurity class
}
class ApplicationBusinessLogic extends MyApplicationBase{
// business logic methods here which may use base class vars like $db
// this may also use instance of ApplicationSecurity class
}
class ApplicationTemplating extends MyApplicationBase{
protected function outputHeader()
{
require_once('path/to/themes/header.php');
}
protected function outputSidebar()
{
require_once('path/to/themes/siderbar.php');
}
protected function outputMainbody()
{
require_once('path/to/themes/mainbody.php');
$app=new ApplicationBusinessLogic();
$app->initiate();
}
protected function outputFooter()
{
require_once('path/to/themes/footer.php');
}
public function outputTemplate()
{
$this->outputHeader();
$this->outputSidebar();
$this->outputMainbody();
$this->outputFooter();
}
}
//index.php file code starts here--------
$myPhpApplication = new ApplicationTemplating();
$myPhpApplication->outputTemplate();
My goal is when I create instance of my application then It only call the single instance of "MyApplicationBase" class instead of calling it multiple times. Please do tell me how can I achieve this. I am google for 5 hours but unable to find any solution yet.
I am trying to develop an object oriented PHP application in which whole php application will be extending from MyApplicationBase base class.
As PHP has single inheritance, this is by far the most worst idea to do object oriented PHP programming.
But the problems is I want to create only single instance of MyApplicationBase.
As every class is a MyApplicationBase you actually don't want that because it would mean you could instantiate exactly one class in your whole application.
What you're probably looking for is some kind of ApplicationClass which you pass along and of which just a single instance exists.
This would at least allow you in the future to throw such a "block in road" away more easily then if you would have got extended from there.
In any case you should program against an ApplicationInterface instead of an ApplicationClass to make this throwing away - as it will be necessary - easier.
The best thing for sure would be to not do anything in that direction and only write code you need in the first place.
To only write code you need, you need to develop test-driven. Why not start with that if you want to do object oriented programming?
Well I suppose that you want to avoid multiple connections to the database in this case. Solution is simple with Dependency injection, just initialize your database connection outside of MyApplicationBase class and then pass it as a constructor parameter (beware of constuctor hell though). Like this:
class MyApplicationBase{
static $called=0;
public $db;
function __construct($db)
{
self::$called++;
echo "<pre>MyApplicationBase Created ".self::$called." times</pre>";
$this->db= $d;
}
}
$db = new DatabaseWrapper();
$templating = new ApplicationTemplating($db);
$security = new ApplicationSecurity($db);
You could also take a look at some framework, they usually come with some dependency injection capabilities.
I have a class named DataBoundObject which is quite big. And works good. Its an ORM class i have developed. One of its functions is to automatically do the setXXX() and getXXX() functions so that no coding is required. The following function does that
public function __call($strFunction, $arArguments) {
$strMethodType = substr ( $strFunction, 0, 3 );
$strMethodMember = substr ( $strFunction, 3 );
if(!is_callable(array($this, $strFunction)))
throw new Exception("Function cannot be called!");
switch ($strMethodType) {
case "set" :
return ($this->SetAccessor ( $strMethodMember, $arArguments [0] ));
break;
case "get" :
return ($this->GetAccessor ( $strMethodMember ));
break;
default :
throw new Exception ( "Non existent method call dude!" );
}
return false;
}
Now in a class which derives this i override one function like this:
<?php
require_once ('DataBoundObject.php');
/**
* ORM extension of BUBBLES_HOTEL_REVIEWS Tabel
* #author footy
* #copyright Ajitah
*
*/
class reviews extends DataBoundObject {
protected $ReviewID;
//Other codes
private function setReviewID($ReviewID) {
throw new Exception ( "Cannot set the review ID Explicitly" );
}
//Other codes
//Other codes
//Other codes
//Other codes
//Other codes
}
$x = new reviews();
$x->setReviewID(5);
?>
Thus finally i create a new object and try to call setReviewID() function which is private. Why is it not generating any Exception? Besides is_callable() is returning true!
EDIT
Mainly i need help to correct this problem so that it throws an Exception
You can't override private methods using __call magic in PHP. I allow myself to quote from php.net website http://php.net/language.oop5.visibility#92995, where your question is perfectly answered in a comment:
In the overriding, the method names and arguments (arg’s) must be
same.
final methods can’t be overridden.
private methods never participate in the in the overriding because
these methods are not visible in the child classes.
While overriding decreasing access specifier is not allowed
If you desperately need this feature - your (unconventional) options will be:
Use public scope for the method, documenting the function of its restrictions for other developers in PHPDoc string.
You can use PECL extensions like runkit sandbox http://php.net/book.runkit
Go for code generation or preprocessor.
Choose a different language.
EDIT
Note that, protected child method is also hidden form the parent, but there is always an option of overriding __call() in a child. Generally, making too much "magical" overrides may be a bad taste for such a serious undertaken as ORM design.
PS
I believe eventually developing a DSL could be an ultimate goal for your project. Before doing so, continuing your project is a nice way to gather respective experience. GL!