PHP Class Extensions - php

I was just wondering if the next situation could be possible or not, I've read the PHP Manual documentation, but I would like another perspective because it's not so clear for me.
So I have for example one class:
class SomeClass {
public function someFunction() {
...
}
}
And an extension of it:
class Extension extends SomeClass {
public function someOtherFunction() {
...
}
}
My question is, could I be able to use the public functions inside the classes on both ways, the main class's function inside the extended function and the other way around?
And would I be doing that how?

You can use both functions from class Extension, but only someFunction() from class SomeClass.
Extension does not change the original class, it just incorporates it into a new one.

You can use the public and protectedfunctions of your parent in the extended (child) class:
class Extension extends SomeClass
{
public function someOtherFunction() {
$foo = $this->someFunction(); // from parent class
return $foo;
}
}
When class "Extension" is created, its basically a copy of "SomeClass" which you can modify in the way as you can add new functions or overwrite those of the parent class.
The parent does not know about the Extension (it can be extended multiple times, eg "JSONRequest extends Request", "XMLRequest extends Request"). Calling extended functions from within the parent makes no sense, since the parent class can never know which childs function it should call in such a situation. This type of Inheritance is one of the basic concepts of OOP and clear interfaces.
In other words, no it will never work the other way round. And it should not.

Related

Making a static function visible only through child class

Let's say that I have some functions in my abstract parent class. I want these to only be accessible by the children classes, so I mark the functions protected (non-static).
abstract class ParentClass
{
protected function myFunction()
{
//implementation
}
}
My problem is the following: I have a few children classes and most of them use the aforementioned protected functions. I want to create a child class though, which allows the programmer to use those functions directly.
So basically:
class ChildClass extends ParentClass
{
public static function myAwesomeFunction()
{
parent::myFunction();
}
}
This is what I want to do. I want the user to be able to call the function (can be with the same name - myFunction in the child class) in a static way from the child class, but not from the parent class (that's why I don't want to make the function public, plus since I want it to be static, marking the class abstract doesn't help with this).
To be able to call
ChildClass::myAwesomeFunction();
but not to be able to do
ParentClass:myFunction();
Is there a trick to achieve this? If not, what is the best practice to do this? Is the only way really to enumerate all the functions I want and have them call the parent's method (like I have in my example)?
You could define the abstract to be protected static and then use the self keyword in the child:
abstract class A
{
protected static function _foo() {
echo "foo\n";
}
}
class B extends A
{
public static function foo() {
self::_foo();
}
}
A::_foo(); // fatal
B::foo(); // works
Given that, I'm not really crazy about this technique, and I would generally recommend avoiding static methods -- then it simply becomes a matter of defining the abstract protected and letting the child inherit it.

How to access class members in traits (or get a similar behaviour)?

This is a follow-up to my previous question about resolving the diamond issue in php.
As I state in that question, I resolve my problem by using traits and passing the instance of the class to the method of the trait. Such as:
trait SecurityTrait
{
public function beforeExecuteRouteTrait($controller, Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
return $this->beforeExecuteRouteTrait($this, $dispatcher);
}
}
However, I am still uncomfortable with this as I don't think this is how traits are really supposed to be used. In my reading I haven't found any way in which to access class members in traits (make $this inside a trait refer to the class using it). Is this possible? Or is there another way to implement a similar behaviour?
After reading some of the answers...
Previously I thought I had received errors when using $this->... inside the trait and this led me to believe the trait could not access anything to do with the underlying class. After reading the answers I tried altering my code to use $this->... inside a trait again and it works - which means a typo several weeks ago has given me far too much headache...
The example given previously now looks like this
trait SecurityTrait
{
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
}
Much cleaner and more easily understandable but provides the same functionality.
If you use a trait inside a class then that trait has full access to all class's members and vice versa - you can call private trait methods from the class itself.
Think of traits as code that literally gets copy/pasted into the class body.
For example:
trait Helper
{
public function getName()
{
return $this->name;
}
private function getClassName()
{
return get_class($this);
}
}
class Example
{
use Helper;
private $name = 'example';
public function callPrivateMethod()
{
// call a private method on a trait
return $this->getClassName();
}
}
$e = new Example();
print $e->getName(); // results in "example"
print $e->callPrivateMethod(); // results in "Example"
In my view referencing classes in traits is not the best way to use them but there's nothing stopping anyone from doing it.
No, that's exactly what Traits are for. Your class already extends a class so you can't inherit the methods and variables of any other classes.
Think of a Trait like copy/paste for code execution. When a class includes a Trait, it's just as if you had written all that code into the class itself.

silverstripe init() function

Can someone explain this code in Silverstripe:
public function init() {
RSSFeed::linkToFeed($this->Link() . "rss");
parent::init();
}
What exactly is init function?
what parent::init();
exactly do in code
in php classes when you overwrite a method of parent class you still can call the parent class with this code, it will help you to put some code at the beginning of the real method without removing it.
you can find out more about it at php documentation
The upmost init() method is defined in the Controller class.
Then ContentController extends Controller, which overrides the Controller class's init() method, but it's also calling parent::init() on the first line. Then usually you define all your page controller classes like this (for any new page type), in the example below for the default Page_Controller class:
class Page_Controller extends ContentController {
public function init() {
parent::init();
// do your own stuff here
}
}
So this is the traditional PHP based class extension mechanism, but Silverstripe also allows you to use Extensions and Data Extensions, which is basically extending the functionality of already existing controllers, data objects. I won't go into details with this... You can find out more about this here: https://docs.silverstripe.org/en/4/developer_guides/extending/extensions/
I usually have something like this in my controller classes:
class Page_Controller extends ContentController {
public function init() {
parent::init();
// do your own stuff here
$this->extend('updateInit');
}
}
Notice the $this->extend('updateInit'); line above.
I can have another extension defined for the Page_Controller class inside a YAML config file somewhere, and than have the updateInit() method defined in that class. Example:
class Page_Controller_Extension extends Extension {
public function updateInit() {
// do some more stuff here
}
}
...and in this case you would have something like this in a YAML config file:
---
Name: siteextensions
After:
- 'framework/*'
- 'cms/*'
---
Page_Controller:
extensions:
- Page_Controller_Extension
Note that this is not really the traditional way of extending classes, like in PHP, it's more like defining some decorators for a controller class. Also, to refer to the parent, or object being decorated, you can't use just $this, you'll need to use $this->owner. Example below:
class Page_Controller_Extension extends Extension {
public function updateInit() {
// do some more stuff here
if ($this->owner->IsFeatured) {
// do something here
}
}
}
You usually decorate controllers extending the Extension class, and you extend the DataExtension class if you want to decorate DataObjects - works the same way as explained above.

Conditional Declaring of Extending Class (Overwriting) Method, Based on the Parent Method's Default Parameters

I am creating a plugin for a CMS that provides a few base classes (let's say one of these classes is called Base). This class has a few helper methods that must be overwritten in the extending class. We should note that the base methods have default parameters/values provided. In one version of the LMS these values are provided by reference in the next version just by value.
For example (CMS v1.0):
function prepareTable(&$table){...
CMS v1.1:
function prepareTable($table){...
When you extend the Base class and overwrite the prepareTable method you have to declare it with the same default parameters/values as well, otherwise a STRICT PHP warning is displayed (on by default in PHP 5.4).
My question is, how do I conditionally overwrite the method from the parent class in a working way, knowing the version of the parent CMS?
Here's what I have currently (not working at the moment):
class Base{
function prepareTable(&$table){
}
}
class Extending extends Base{
if(CMS_VERSION=='1.0')
function prepareTable(&$table){
else
function prepareTable($table){
echo $table;
}
}
Obviously, I can not edit the Base and its method directly.
EDIT: Here's the exact error message:
Strict standards: Declaration of Extending::prepareTable() should be compatible with Base::prepareTable($table) in.
the only way I can think of achieving this without duplicating the code inside prepareTable is to create a pseudo function that gets called inside prepareTable and then declare that in the final extended class
if(CMS_VERSION=='1.0') {
class Base2 extends Base{
function prepareTable(&$table){
return $this->prepareTable2($table);
}
function prepareTable2(&$table){
}
}
} else {
class Base2 extends Base{
function prepareTable($table){
return $this->prepareTable2($table);
}
function prepareTable2(&$table){
}
}
}
class Extending extends Base2{
function prepareTable2(&$table){
echo $table;
}
}
if(CMS_VERSION=='1.0') {
class Extending extends Base{
function prepareTable(&$table){
}
}
} else {
class Extending extends Base{
function prepareTable($table){
}
}
}
Note that the if/else check must be done before the class is defined, not inside the class. Essentially, you are building two different versions of the class.
Side Note: If you need to include shared methods, that won't be changed between the two versions of the class, you can define a new class that will extend Extending, create the shared methods there and use this new class.
For example (place this after the code above):
class ExtendingFull extends Extending{
// Here you may include your shared methods
// e.g:
public function sharedMethod(){
echo 'test';
}
}

Parent class inheritance of child class functions

I'm writing a power plugin for wordpress that basically supplies a bunch of functions to make development easier.
Don't worry about the wp stuff though, this is a PHP question. I have one master class 'my_wp_funcs', and a few other large classes that do different things, which I've written separately and work on their own, for example: insert a new post.
I would like to be able to use this syntax:
$wpfuncs = new funcs;
$wpfuncs->createpost($args);
$wpfuncs->addimage();
where createpost class extends funcs class, along with other classes that extend funcs too.
I've been reading up on abstraction, but am getting continual errors. Here's a trimmer version of what I have:
<?php
$wpfuncs = new funcs;
$wpfuncs->createpost($args);
abstract class funcs
{
abstract protected function createpost();
public function createpost($args){
$tool = new $this->boss_posttype('derp', 'derps');
}
}
class createpost extends funcs{
public function __construct(){
//do stuff
}
}
Cheers for any help!
You can't define the method as abstract in the abstract class and then define it for real in the same class. You also can't call the abstract class directly.
You probably want something like this:
abstract class funcs
{
abstract public function createpost($args);
}
class myFuncs {
public function createpost($args){
$tool = new $this->boss_posttype('derp', 'derps');
// do other stuff
}
}
$wpfuncs = new myFuncs();
$wpfuncs->createpost($args);
Note that your implementation goes in your own class, and that implementation has to match your abstract definition. (they both have to be public and they have to accept the same arguments)

Categories