Some code first...
FlashBagUtil class containing the constants:
class FlashBagUtil
{
const TYPE_NOTICE = 'notice';
const TYPE_WARNING = 'warning';
const TYPE_ALERT = 'alert';
const LANG_EN = 'en';
const LANG_RU = 'ru';
const LANG_IL = 'il';
}
Parent class:
class CoreController
{
public $flashUtil;
public function __construct()
{
$this->flashUtil = new FlashBagUtil;
}
}
Child class:
class BatchController extends CoreController
{
public function indexAction()
{
// Method 1 - This works fine
$flash = $this->flashUtil;
$flashType = $flash::TYPE_NOTICE;
// Method 2 - This, obviously, does not
$flashType = $this->flashUtil::TYPE_NOTICE;
// Method 3 - Neither does this as $flashUtil is a non-static instantiated object
$flashType = self::$flashUtil::TYPE_NOTICE;
}
}
PHP documentation states: A property declared as static cannot be accessed with an instantiated class object (though a static method can).
But I seem to be able to do that with the first method. What am I missing?
+
Is Method 1 the only and cleanest way of accessing static content in this context?
You're referencing a class constant, which is different than a class variable (property) and is accessible to instantiated objects. The documentation you're referencing refers to class variables defined with the static keyword (ie. private static $flashUtil;), which may be the source of your confusion if you're accustomed to programming in other more strictly typed OOP languages.
if you want to use your class as enum, make the enumerationsclass abstract:
abstract FlashBagUtil
{
const TYPE_NOTICE = 'notice';
...
}
and use it in your childclass:
class Controller
{
private flashType = FlashBagUtil::TYPE_NOTICE;
}
Making it an abstract class like suggested won't be much of help here, I think, as there are more things going on in FlashBagUtil class that I've removed for the example code.
My Method 1 works but requires making a copy of the original object which defies the purpose of a common inherited object. So...
In the end I've settled on a standard way to access static content directly by importing the namespace to child class and use $flashType = FlashBagUtil::TYPE_NOTICE as suggested by Ralphael. Would've been nice to access the constants from the object in a one liner, but this keeps static content nicely separated as well.
Full child class:
use TreasureForge\CoreBundle\Util\FlashBagUtil;
class BatchController extends CoreController
{
public function indexAction()
{
$flash = FlashBagUtil::TYPE_NOTICE;
}
}
Many thanks for your input.
Related
In C# I can create static class that have inside a couple of static classes that I can use as namespaces for constants, for example:
public static class ConstantTypes{
public static class ErrorTypes{
public static string Log = "Log";
}
}
Than in app I can use:
ConstantTypes.ErrorTypes.Log
How to do the same in PHP in Laravel?
Now I created two classes:
class LogTypeConstants
{
const MYCONST = 'val';
}
use App\Common\LogTypeConstants;
class AppConstants
{
static function LogTypes() {
$logTypeConstants = new LogTypeConstants();
return $logTypeConstants;
}
}
And in Laravel controller I can use:
$logType = AppConstants::LogTypes()::MYCONST;
Is better way to do the same?
Bold statement, never create static functions unless absolute necessary, a nightmare with dependency injection. With that out of the way, what i feel is the consensus on this, is just to use the constants and access them on the class.
class LogTypeConstants
{
public const MYCONST = 'val';
}
LogTypeConstants::MYCONST; // would access it
An perfect example is how Symfony implements their HTTP status codes on the Response class. In Laravel you would access it like so.
use Illuminate\Http\Response;
public function store() {
...
return $this->response($object, Response::HTTP_CREATED);
}
I just have a simple question here... I was working on developing a forum application for my website, and while updating some of the old methods I used (my old code is horrid) I came across - not for the first time - OOP devices.
I have quite a few classes that my system uses, and redefining the same function(s) for them over and over, so I decided to create a base class that would carry the functionality.
I've been trying to use require() on the base class then extend the class off of it...
<?php
require(//path to base class);
class User extends BaseClass {
// code
}
?>
But I don't know how to check if it's there, and it doesn't seem to be inheriting the base class's only function...
public function __get($what) {
if(property_exists($this, $what)) {
return $this->{$what};
} else {
return null;
}
}
Since when I try to retrieve a variable from the User class (e.g. $user->Username) it returns NULL. The variable is marked as private in the class, but before I tried to do inheritance that wasn't an issue.
It sounds like you are wanting to get after your variables in your parent class but do not want to use getter methods to do so. Marking these variables protected will indeed allow your child classes access to those properties, but in cases where you want your base class to enforce processing before setting/getting, marking the properties protected will not cut it.
In your case it sounds like you are marking your variables protected as a workaround. However you can still use private variables in your base class and allow access to them in your child classes as follows:
class BaseClass
{
private $strValue = "We the people....";
public function __get($what)
{
if(isset($this->{$what})) {
return $this->{$what};
}
return null;
}
}
class ChildClass extends BaseClass
{
private $intValue = 255;
public function __get($what)
{
if(isset($this->{$what})) {
return $this->{$what};
} else if(parent::__get($what) != null) {
return parent::__get($what);
}
return null;
}
}
//Try it out
$child = new ChildClass();
var_dump($child->strValue); //"We the people...."
var_dump($child->intValue); //255
In this example the BaseClass uses the __get() magic method to lookup its own properties and the ChildClass overrides it to do the same. In the ChildClass if it cannot find a requested property, then it diverts to the parent's version.
As long as you don't override your properties you can use private variables throughout and access them as if they were public outside of your class scope.
just use
class_exists() to make sure your class is there.
This might be basic knowledge, but I am curious as I do not know it yet myself. Why in PHP (and assuredly other languages) when using classes must a child class use a construct method to access the parent class' properties. In case this is unclear I will include an example.
<?php
class aClass
{
protected $aProperty = "Some value";
}
class aDifferentClass extends aClass
{
public $aDifferentProperty;
public function __construct()
{
$this->$aDifferentProperty = $this->aProperty;
}
?>//Works.
Instead of:
<?php
class aClass
{
protected $aProperty = "Some value";
}
class aDifferentClass extends aClass
{
public $aDifferentProperty = $this->$aProperty;
}
?>//Doesn't work.
Its not a matter of needing the constructor its a matter of WHEN you're trying to access it. A class is a blueprint for an object -- when you're trying to assign the property, as you've done in your example above, ie.
public $aDifferentProperty = $this->aProperty;
There is no object, and thus "this" does not yet exist. But, instead, this would work:
class A {
protected $a_property = "BOOYEA!";
}
class B extends A {
public function show_me_a_prop() {
echo $this->a_property;
}
}
$object = new B();
$object->show_me_a_prop();
So, to answer your question, you must wait until after the object has been constructed to access the properties because until its constructed, its not an object, just a blueprint for an object.
Now, to take this a bit further, you'd not allowed to assign variables directly to properties (see http://php.net/manual/en/language.oop5.properties.php ) but you can assign a constant. So here's a similar example which does work:
class A {
const a_property = "BOOYEA!";
}
class B extends A {
public $b_property = self::a_property;
}
$object = new B();
echo $object->b_property;
The "__construct" was introduced in PHP5 and it is the right way to define your constructors (in PHP4 you used the name of the class for a constructor).
You are NOT REQUIRED to define a constructor in your class, but if you wish to pass any parameters on object construction THEN YOU NEED ONE.
Also...If further down the track you change the class the child class inherits from, you don't have to change the construct call to the parent.
much easier to call parent::__construct() instead of parent::ClassName(), as it is reusable among classes and the parent can be changed easily.
In other OO languages like Java we can override a function, possible using keywords/annotations like implements, #override etc.
Is there a way to do so in PHP? I mean, for example:
class myClass {
public static function reImplmentThis() { //this method should be overriden by user
}
}
I want user to implement their own myClass::reImplementThis() method.
How can I do that in PHP? If it is possible, can I make it optional?
I mean, if the user is not implementing the method, can I specify a default method or can I identify that the method is not defined (can I do this using method_exists)?
<?php
abstract class Test
{
abstract protected function test();
protected function anotherTest() {
}
}
class TestTest extends Test
{
protected function test() {
}
}
$test = new TestTest();
?>
This way the class TestTest must override the function test.
Yes, there is. You have the option to override a method by extending the class and defining a method with the same name, function signature and access specifier (either public or protected) it had in the base class. The method should not be declared abstract in the base class or you will be required to implement it in the derived class. In you example it would look something like this:
class MyClass {
public static function reImplmentThis() { //this method should be overriden by user
}
}
class MyDerivedClass extends MyClass {
public static function reImplmentThis() { //the method you want to call
}
}
If the user does not overrides it, MyDerivedClass will still have a reImplmentThis() method, the one inherited from MyClass.
That said, you need to be very careful when invoking extended static methods from your derived class to stay out of trouble. I encourage you to refactor your code to extend instance methods unless you have a very specific need to extend static classes. And if you decide there is no better way than extending static classes please be sure to understand Late Static Binding pretty well.
Yes, its possible to check if the method is implemented or not and get a whole lot more of information about a class using PHP Reflection.
This touches on several OOP subjects.
First, simply overriding an method declared in a parent class is as simple as re-declaring the method in an inheriting class.
E.g:
class Person {
public function greet(string $whom) {
echo "hello $whom!";
}
}
class Tommy extends Person {
public function greet(string $whom = "everyone") {
echo "Howdy $whom! How are you?";
}
}
$a = new Tommy();
$a->greet('World');
// outputs:
// Howdy World! How are you?
If on the overriding method you wan to reuse the logic of the overriden one, it's just a matter of calling the parent's method from the extending class::
class Tommy
{
public function greet(string $whom)
{
// now with more emphasis!!!
echo parent::greet(strtoupper($whom)) . "!!!!";
}
}
Now Tommy::greet() calls Person::greet(), but modifies the result before returning it.
One thing to note is that overriding methods have to be compatible with the overriden one: the method visibility can't be more restrictive than the original one (it's OK to increase visibility), and the number and type of required arguments can't conflict with the original delcaration.
This works, because the type of the arguments does not clash with the original, and we have less required arguments than on the parent:
class Leo extends Person {
public function greet(string $whom = "gorgeous", string $greet = "Whatsup" ) {
echo "$greet $whom. How are you?";
}
}
But this doesn't, since there are additional required arguments. This would make impossible to switch the original class for this one transparently, and thus would throw a Warning:
class BadBob extends Person {
public function greet(string $whom, string $greet ) {
echo "$greet $whom. How are you?";
}
}
Additionally, you mention in your question that "this method should be overriden by the user". If you require client classes to actually implement the method, you have a couple of options:
Abstract classes & methods
These are methods where the implementation is left empty, and that extending classes have to implement to be valid. In we changed our original class Person to:
abstract class Person {
public function greet(string $whom) {
echo "hello $whom!";
}
public abstract function hide();
}
Since now the class contains an abstract method, it needs to be declared as an abstract class as well.
Now it is not possible to instantiate Person directly, you can only extend it in other classes.
Now all our existing Person extending classes would be wrong, and trying to execute the previous code would throw a fatal error.
An example of a valid class extending Person now would be:
class Archie extends Person {
public function hide() {
echo "Hides behind a bush";
}
}
Any class that extends Person must declare a public hide() method.
Interfaces
Finally, you mention interfaces. Interfaces are contracts that implementing classes have to fulfill. They declare a group of public methods without an implementation body.
E.g.:
interface Policeman {
public function arrest(Person $person) : bool;
public function help($what): bool;
}
Now we could have class that extended Person and implemented Policeman:
class Jane extends Person implements Policeman {
public function hide() {
echo "Jane hides in her patrol-car";
}
public function arrest(Person $person): bool{
// implement arrest method
return false;
}
public function shoot($what): bool {
// implements shoot() method
return false;
}
}
Importantly, while it's possible to extend only one class (there is no multiple inheritance in PHP), it is possible to implement multiple interfaces, and the requirements for each of those have to be fulfilled for the class to be valid.
I've seen a few questions with really similar titles but they where irrelevant to my specific problem.
Basically, I want to access the variables from my core class in a class which extends core, but things seem to be quite complicated compared to other examples. I am using a MVC framework. I've simplified the code below to remove anything that was irrelevant.
index.php
// Load the core
include_once('core.php');
$core = new Core($uri, $curpath);
$core->loadController('property');
core.php
class Core
{
public $uri;
public $curpath;
function __construct($uri, $curpath)
{
$this->uri = $uri;
$this->curpath = $curpath;
}
// Load the controller based on the URL
function loadController($name)
{
//Instantiate the controller
require_once('controller/'.$name.'.php');
$controller = new $name();
}
}
property.php
class Property extends Core
{
function __construct()
{
print $this->curpath;
}
}
Printing $this->curpath just returns nothing. The variable has been set but it is empty.
If I print $this->curpath inside core.php it prints fine.
How can I access this variable?
You are doing it wrong tm
You should be utilizing an autoloader, instead of including files with each class manually. You should learn about spl_autoload_register() and and namespaces, and how to utilize both of them.
Do not generate output in the __construct() methods. That's an extremely bad practice
The variables are still there. That is not the problem. In PHP, when you extend a class, it does not inherit the constructor.
You do not understand how inheritance works. When you call method on instance of extended class it will not execute parent class's method , before calling extended class's methods. They get overwritten , not stacked.
Object variables should not be exposed. You are breaking the encapsulation. Instead og defining them as public you should use protected.
You should extend classes of they are different type same general thing. The extends in PHP means is-a. Which means that, when you write class Oak extends Tree, you mean that all the oaks are trees. The same rule would mean, that in your understanding all Property instances are just a special case of Core instances. Which they clearly ain't.
In OOP, we have principle. One of which is Liskov substitution principle (shorter explanation). And this is the thing your classes are violating.
The problem, I think, lies here:
If you consider a simple inheritance like this one:
class Dog{
public $color;
public function __construct($color){
$this->color = $color;
}
}
class TrainedDog extends Dog{
public $tricks;
public function __construct($color, $tricks){
$this->tricks = $tricks;
parent::__construct($color);
}
}
//Create Dog:
$alfred = new Dog('brown');
//Create TrainedDog
$lassie = new TrainedDog('golden',array('fetch'));
In this example $alfred is a brown dog and $lassie is a golden dog. The two instances are separate from each other, the only thing they have in common is that they both have a property called $color.
If you want a variable that is available in all Dogs for example, you need a class variable:
class Dog{
public $color;
public static $numberOfLegs; //Class variable available in every instance of Dog.
public function __construct($color, $numberOfLegs){
$this->color = $color;
self::$numberOfLegs = $numberOfLegs;
}
}
class TrainedDog extends Dog{
public $tricks;
public function __construct($color, $tricks){
$this->tricks = $tricks;
parent::__construct($color);
echo parent::$numberOfLegs;
}
}
This does not make much sense in many cases though, because if you have two instances of the parent class (in you're case Core), they also share the class variable.
Unless you can ensure that Core is instanciated only once, this approach will not work. If it does only exist once, you can just as well use constant variables to store the 2 properties.
If there exist multiple instances/objects of Core, I'd recommend using a composition (as suggested by Alvin Wong).
class Core{
//Just as you programmed it.
}
class Property{
private $core;
public function __construct($core){
$this->core = $core;
echo $core->curPath;
}
}
Try this
include_once('core.php');
$core = new Core('test', 'path');
$core->loadController('property');
class Property extends Core
{
function __construct($date)
{
print $date->curpath;
}
}
class Core
{
public $uri;
public $curpath;
function __construct($uri, $curpath)
{
$this->uri = $uri;
$this->curpath = $curpath;
}
// Load the controller based on the URL
function loadController($name)
{
//Instantiate the controller
require_once($name.'.php');
$controller = new $name($this);
}
}