I have a sample code in php
class First {
public static $name;
public static function getName() {
return static::$name;
}
}
class Second extends First {
public static $name = 'second';
}
echo Second::getName(); // print 'second'
But when I write it into fuelphp:
File 1:
namespace Model;
use \DB;
class ModelMain extends \Model {
public static $table_name;
public static function getName() {
return self::$table_name;
}
}
File 2
class Post extends \Model\ModelMain {
public static $table_name = "post";
}
When I call
Post::getName() // Print null
I expected it will print post. What is wrong with it?
It returns null since the $table_name is not assigned , Instead you should add return static::$table_name; inside the getName() of the ModelMain class to enable the Late Static Binding , so it does displaypost as output.
Late Static Binding...
<?php
namespace Model;
use \DB;
class ModelMain extends \Model {
public static $table_name;
public static function getName() {
return static::$table_name; //<--- Add static here to introduce LSB
}
}
class Post extends \Model\ModelMain {
public static $table_name = "post";
}
echo Post::getName();
Related
Suppose I have the following :
<?php
class Final extends Intermediate {
public function final_level() {
$this->low_level();
$this->inter_level();
}
}
class Intermediate extends Lib1 {
public function inter_level() {
$this->low_level();
}
}
class Lib1 {
public function low_level1();
public function low_level2();
}
class Lib2 {
public function low_level1();
public function low_level2();
}
I would like to change the Intermediate class to extend Lib1 or Lib2, depending on some conditions, without duplicating Intermediate and Final code content.
All low_level functions are the same for both Lib.
In the end, I would like to have a Final1 class that use Lib1 (and Final2 that use Lib2).
How could I achieve this ?
You cannot achieve this via inheritance but you can via delegation
With this approach you delegate the implementation of some methods to a 'delegate' object rather than a base class.
Here it is an example:
<?php
class Final extends Intermediate {
public function __construct(Lib delegate) {
parent::__construct(delegate);
}
public function final_level() {
$this->low_level();
$this->inter_level();
}
}
class Intermediate implements Lib { //here you implement an interface rather than extending a class
private Lib delegate;
public function __construct(Lib delegate) {
$this->delegate = delegate;
}
public function inter_level() {
$this->low_level();
}
public function low_level() {
//delegate!
$this->delegate->low_level();
}
}
class Lib1 implements Lib{
public function low_level(); //implementation #1
}
class Lib2 implements Lib {
public function low_level(); //implementation #2
}
interface Lib {
public function low_level();
}
now you can create your final1 and final2 object in this way:
$final1 = new Final(new Lib1());
$final2 = new Final(new Lib2());
or, if you prefer, you can create the Final1 and Final2 classes extending from Final:
class Final1 extends Final {
public function __construct()
{
parent::__construct(new Lib1());
}
}
class Final2 extends Final {
public function __construct()
{
parent::__construct(new Lib2());
}
}
$final1 = new Final1();
$final2 = new Final2();
I have a base class which sets up's other extending controllers like this:
class BaseController extends Controller
{
public $globalCurrencies;
public $globalLanguages;
public function __construct()
{
$this->globalCurrencies = $this->getCurrencies(); // this works
$this->globalLanguages = $this->getLanguages(); // this works
}
}
And I use one of helpers to extend this class like this:
class SessionHelper extends BaseController
{
public $test;
public function __construct()
{
parent::__construct(); // fire parent aka basecontroller construct
$this->test = $this->globalCurrencies; // this works (variables are set)
echo '__construct: '.$this->test; // this even displays it
}
public function getCurrencies()
{
dd('method'.$this->test); // NOT WORKING
}
public function getCurrentCurrency()
{
return $this->getCurrencies()->where('id', Session::get('currencyId'))->first() ?? null;
}
}
Later on code is used in model:
class Product extends Model
{
protected $table = "products";
public $timestamps = true;
public $sessionHelper;
public function __construct()
{
$this->sessionHelper = new SessionHelper;
}
public function getPrice($conversion_rate = null)
{
return number_format($this->price_retail / $this->sessionHelper->getCurrentCurrency()->conversion_rate, 2);
}
}
Have any body idea why I can access in construct variable but not in method? If i remember correctly construct is fired first so everything after should have access to it.
Declare $test variable as private out side the constructor. Inside the constructor keep it the way you are doing it right now and then make a setter and getter for the test variable.
class testObject
{
private $test;
function __construct($test)
{
$this->test= $this->globalCurrencies;
}
// test getter
function getTest()
{
return $this->test;
}
}
Change your method to be;
public function getCurrencies()
{
dd('method', $this->test);
}
You can not concatenate strings and objects/arrays.
If that doesn't resolve the issue - check the laravel.log
I'm really bad at OOP and I can't work out this inherited code I've been given.
This is part of the generic Model class;
abstract class Model
{
protected static $_tableName = false;
protected static $_itemName = false;
public static function tableName()
{
return static::$_tableName;
}
public static function itemName()
{
return static::$_itemName;
}
How do I set the tablename in the Class that I have created???;
class Payments extends Model {
//public $_tableName;
public function __construct()
{
$this->$_tableName = 'payments'; //line 13
}
}
I get an error Undefined variable: _tableName in /var/www/html/lib/Local/Models/Payments.php on line 13 when I don't set it as a parameter. and an error Cannot redeclare static XXX\Model::$_tableName when I do.
UPDATE
When I try to use the find method with this abstract Model, it's not setting the tableName;
public static function find($idOrWhere = false, $params = array(), $limit = false)
{
$sql = "SELECT * FROM " . static::tableName();
I don't know how to set that now. It just ignores what I have put in my class.
You have to remove the $ when accessing a class property:
class Payments extends Model
{
public function __construct()
{
$this->_tableName = 'payments';
}
}
Indeed this is irritating, but that's the way php syntax works.
With static class you need to use the self keyword to initialize property in class:
class Foo {
static $bar;
}
Foo::$bar = array(…);
or
class Foo {
private static $bar;
static function init()
{
self::$bar = array(…);
}
}
Foo::init();
I have the following two classes. Class BMW extends class Car.
class Car{
public $doors;
public $wheels;
public $color;
public $size;
public function print_this(){
print_r($this);
}
}
class BMW extends Car{
public $company;
public $modal;
public function __construct(){
print_r(parent::print_this());
}
}
$bmw = new BMW();
$bmw->print_this();
In above code when I access parent class method from constructor using parent::print_this() and inside print_this() method I have print_r($this) which prints all properties(parent and child class properties)
Now what I want print_r(parent::print_this()); should output only parent class properties in child class? Can anyone help me on this?
You can achieve this using reflection:
class Car{
public $doors;
public $wheels;
public $color;
public $size;
public function print_this(){
$class = new ReflectionClass(self::class); //::class works since PHP 5.5+
// gives only this classe's properties, even when called from a child:
print_r($class->getProperties());
}
}
You can even reflect into the parent class from a child class:
class BMW extends Car{
public $company;
public $modal;
public function __construct(){
$class = new ReflectionClass(self::class);
$parent = $class->getParentClass();
print_r($parent->getProperties());
}
}
Edit:
what actually I want that whenever I access print_this() method using object of class BMW it should print BMW class properties only and when I access print_this() from BMW class using parent it should print only parent class properties.
There are two ways of making the same method behave differently: Overriding it in the child class or overloading it / passing flags to it. Since overriding it would mean a lot of code duplication (you would have to to basically the same in each child class) I would suggest you build the print_this() method on the parent Car class like this:
public function print_this($reflectSelf = false) {
// make use of the late static binding goodness
$reflectionClass = $reflectSelf ? self::class : get_called_class();
$class = new ReflectionClass($reflectionClass);
// filter only the calling class properties
$properties = array_filter(
$class->getProperties(),
function($property) use($class) {
return $property->getDeclaringClass()->getName() == $class->getName();
});
print_r($properties);
}
So now, if you explicitly want to print the parent class properties from a child class, just pass a flag to the print_this() function:
class BMW extends Car{
public $company;
public $modal;
public function __construct(){
parent::print_this(); // get only this classe's properties
parent::print_this(true); // get only the parent classe's properties
}
}
Try
public function print_this()
{
$reflection = new ReflectionClass(__CLASS__);
$properties = $reflection->getProperties();
$propertyValues = [];
foreach ($properties as $property)
{
$propertyValues[$property->name] = $this->{$property->name};
}
print_r($propertyValues);
}
You could try something like this:
class Car{
public $doors;
public $wheels;
public $color;
public $size;
public function print_this(){
print_r(new Car());
}
}
Or this:
class Car{
public $doors;
public $wheels;
public $color;
public $size;
public $instance;
public function __constructor(){
$this->instance = new Car;
}
public function print_this(){
print_r($this->instance);
}
}
This is probably a basic question but im following this tutorial and at one point the code looks something like this.
<?php
class person
{
public $name;
public $height;
protected $social_security_no;
private $pin_number = 3242;
public function __construct($person_name)
{
$this->name = $person_name;
}
public function set_name($new_name)
{
$this->name = $new_name;
}
protected function get_name()
{
return $this->name;
}
public function get_pin_number_public()
{
$this->pub_pin = $this->get_pin_number();
return $this->pub_pin;
}
private function get_pin_number()
{
return $this->pin_number;
}
}
class employee extends person
{
public function __construct($person_name)
{
$this->name = $person_name;
}
protected function get_name()
{
return $this->name;
}
}
However when i use this
<?php include "class_lib.php";?>
</head>
<body id="theBody">
<div>
<?php
$maria = new person("Default");
$dave = new employee("David Knowler");
echo $dave->get_name();
?>
i get this error
Fatal error: Call to protected method employee::get_name() from
context '' in C:\Users\danny\Documents\Workspace\test\index.php on
line 13
The problem seems to be when i add protected to the get_name() function in the employee class but it seems to me that this is the preferred way to override in the tutorial. Any ideas?
The problem isn't that you cannot override the protected method, it's that you are calling a protected method from outside of the class.
After the class is instantiated, you can call a public method which in turn could call get_name() and you will see that the code will work as expected.
For example:
class employee extends person {
function __construct($person_name){
$this->name = $person_name;
}
protected function get_name() {
return $this->name;
}
public function name()
{
return $this->get_name();
}
}
$dave = new employee("David Knowler");
echo $dave->name();
In your example, you would probably be best making get_name() public.
"The problem seems to be when i add protected to the get_name() function in the employee class" -- this is your answer. A protected method can only be called from the very same class or subclasses, not "from the outside". Your method has to be public if you want to use it this way.
You can access get_name() within person class or employee class not outside of these two classes.
check protected visibility
http://php.net/manual/en/language.oop5.visibility.php