Late static binding works as not expected - php

Here is the code of registry I'd like to use. But static doesn't work as it should. In this example it always returns 2 (while 1 is expected). What can it be?
<?php
class CommonRegistry{
protected static $register;
public static function show()
{
return static::$register;
}
}
class NewRegister extends CommonRegistry{
public function __construct($num)
{
static::$register = $num;
}
}
class AnotherRegister extends CommonRegistry
{
public function __construct($num)
{
static::$register = $num;
}
}
$a = new NewRegister(1);
$b = new AnotherRegister(2);
var_dump(NewRegister::show());

Related

How to extract variable from one function into another in same class in php

I want to use variable value from one function into another function of same class. I am using abstract class using which I am declaring variable as global indirectly. I can not declare variable as global in the class. My demo code is as follows:
<?php
abstract class abc
{
protected $te;
}
class test extends abc
{
public function team()
{
$te = 5;
$this->te += 100;
}
public function tee()
{
$tee = 51;
return $this->te;
}
}
$obj = new test();
echo $obj->tee();
//echo test::tee();
?>
Is this possible that I can echo 105 as answer there?
My main motive is I want to learn that how to get variable value from one function into another using without declaring that global in the same class Please let me know Is this possible OR I need to delete my question ?
<?php
abstract class abc
{
protected $te;
}
class test extends abc
{
public function __construct() {
$this->te = 5;
}
public function team()
{
$this->te += 100;
}
public function tee()
{
return $this->te;
}
}
$obj = new test();
$obj->team();
echo $obj->tee();
-- edit: to make at least some use of the abstract "feature":
<?php
abstract class abc
{
protected $te;
abstract public function team();
public function tee()
{
return $this->te;
}
}
class test extends abc
{
public function __construct() {
$this->te = 5;
}
public function team()
{
$this->te += 100;
}
}
$obj = new test();
$obj->team();
echo $obj->tee();
-- edi2: since you've asked whether you must invoke team (and then deleted that comment):
<?php
abstract class abc
{
protected $te;
abstract public function team();
public function tee()
{
$this->team();
return $this->te;
}
}
class test extends abc
{
public function __construct() {
$this->te = 5;
}
public function team()
{
$this->te += 100;
}
}
$obj = new test();
echo $obj->tee();
So, yes, it has to be invoked somewhere. But depending on what you're trying to achieve there are numerous ways to do so.
Each property of the class can be accessed by each method of the same class. So you can create methods which are working with the same property. And you don't need to create parent abstract class.
class test
{
protected $te = 5;
public function team()
{
$this->te += 100;
}
public function tee()
{
return $this->te;
}
}
$obj = new test();
$obj->team();
echo $obj->tee();

Overriding and accessing abstract class properties in child class in PHP

interface A
{
public function method1();
public function method2();
}
abstract class B implements A
{
public $publicc = 2;
public function method1()
{
echo "in method1 of B<br>";
}
}
class C extends B
{
public $publicc = 4;
public function __construct()
{
}
public function method2()
{
}
public function method1()
{
echo $this->publicc + parent::$publicc; // error for using parent::$publicc
}
}
$obj = new C();
$obj->method1();
But php throws error echo $this->publicc + parent::$publicc. I just want to get parent class $publicc property directly that has value 2, Without using any accessor method. Is there a way to do this in php?
It depends on what publicc exactly holds but a constant might suit your needs?
interface A
{
public function method1();
public function method2();
}
abstract class B implements A
{
const PUBLICC = 2;
public function method1()
{
echo "in method1 of B<br>";
}
}
class C extends B
{
const PUBLICC = 4;
public function __construct()
{
}
public function method2()
{
}
public function method1()
{
echo self::PUBLICC + parent::PUBLICC; // error for using parent::PUBLICC
}
}
$obj = new C();
$obj->method1();
I think you want a static property. If it is a property you want to access without an instance, that usually indicates a candidate for a static variable.
abstract class B implements A
{
protected static $publicc = 2;
...
}
class C extends B
{
public $publicc = 4;
public function __construct()
{
}
public function method2()
{
}
public function method1()
{
echo $this->publicc + parent::$publicc; // error for using parent::$publicc
}
}

Impossible to assign simple Array on Stackable

I am trying to create a library for codeigniter that uses pthread, everything works fine but when i want to assign a value to an array this don't work with traditional $a['key'] = 'val';
Small Test Exemple : ( updated )
class Test {
protected $core;
protected $stack;
public function init(){
$this->stack = new Test_Stack();
$this->core = new Test_Core($this->stack);
}
public function do_test(){
return $this->core->assign();
}
}
class Test_Stack extends Stackable {
protected $a;
function __construct(){
$this->a = array();
}
protected function test(){ // Call from other class extends Threads
$this->a['key1'] = 'NOWORK';
print_r($this->a); // THIS RETURN NOTHING
$this->a = array_merge($this->a, array('key1' => 'WORK'));
print_r($this->a); // NOW THIS GOOD RETURN Key1..
}
public function run(){}
}
class Test_Core {
protected $thread;
protected $stack;
function __construct($s){
$this->stack = $s;
}
public function assign(){
$this->thread = new Test_Thread($this->stack);
$this->thread->start();
$this->thread->join();
}
}
class Test_Thread extends Thread{
protected $stack;
function __construct($s){
$this->stack = $s;
}
public function run(){
$this->stack->test();
}
}
I write this basic code without testing but it's the same structure of my lib and need this to extends test_stack and add or change test function for exemple.
Even if works now, I would understand why I can't assign my array normally ?
Or rather, what am I doing wrong?
Working in Mine :
class Stack {
protected $a;
function __construct(){
$this->a = array();
}
function test(){
$this->a['key1'] = 'NOWORK';
print_r($this->a); // THIS RETURN NOTHING
$this->a = array_merge($this->a, array('key1' => 'WORK'));
print_r($this->a); // NOW THIS GOOD RETURN Key1..
}
}
$obj = new Stack();
$obj->test();
Output :
Array
(
[key1] => NOWORK
)
Array
(
[key1] => WORK
)
OK array isn't thread safe, should be used stackable, this do the trick :
Libraries/Test.php :
class Test {
protected $core;
protected $stack;
public function init(){
$this->stack = new Test_Stack();
$this->core = new Test_Core($this->stack);
}
public function do_test(){
$this->core->assign();
$this->core->assign();
$this->core->assign();
}
public function get_a(){
return $this->core->get_a();
}
}
class Test_Array_Stack extends Stackable {
public function run(){}
}
class Test_Stack extends Stackable {
protected function test($a){
$a[] = 'WORK';
}
public function run(){}
}
class Test_Core {
protected $thread;
protected $stack;
protected $a;
function __construct($s){
$this->stack = $s;
$this->a = new Test_Array_Stack();
}
public function assign(){
$this->thread = new Test_Thread($this->stack, $this->a);
$this->thread->start();
$this->thread->synchronized(function($thread){
$thread->wait();
}, $this->thread);
return $this->a;
}
public function get_a(){
return $this->a;
}
}
class Test_Thread extends Thread{
protected $stack;
protected $a;
function __construct($s, $a){
$this->stack = $s;
$this->a = $a;
}
public function run(){
$this->stack->test($this->a);
$this->synchronized(function($thread){
$thread->notify();
}, $this);
}
}
You can extends Test_Stack to create lib extension more useful for my project, like this on other file Test_Info.php :
require_once APPPATH.'libraries/Test.php';
class Test_Info extends Test {
function init(){
$this->stack = new Test_Info_Stack();
$this->core = new Test_Core($this->stack);
}
}
class Test_Info_Stack extends Test_Stack {
protected function test($a){
parent::test($a);
$a[] = 'INFO';
}
}
And usage on controller:
function index(){
//without extension
$this->load->library('Test');
$this->test->init();
$this->test->do_test();
print_r($this->test->get_a());
//with extension
$this->load->library('Test_Info');
$this->test_info->init();
$this->test_info->do_test();
print_r($this->test_info->get_a());
}
It took me some time, i hope it will help someone and LuckyBurger thank you for the explanation link.

Switch visibility in php if parameter

I'm wondering if its possible to switch the visibility in PHP. Let me demonstrate:
class One {
function __construct($id){
if(is_numeric($id)){
//Test function becomes public instead of private.
}
}
private function test(){
//This is a private function but if $id is numeric this is a public function
}
}
Is such thing even possible?
I would use an abstract class with two implementing classes: One for numeric and one for non-numeric:
abstract class One {
static function generate($id) {
return is_numeric($id) ? new OneNumeric($id) : new OneNonNumeric($id);
}
private function __construct($id) {
$this->id = $id;
}
}
class OneNumeric extends One {
private function test() {
}
}
class OneNonNumeric extends One {
public function test() {
}
}
$numeric = One::generate(5);
$non_numeric = One::generate('not a number');
$non_numeric->test(); //works
$numeric->test(); //fatal error
It can be faked up to a point with magic methods:
<?php
class One {
private $test_is_public = false;
function __construct($id){
if(is_numeric($id)){
$this->test_is_public = true;
}
}
private function test(){
echo "test() was called\n";
}
public function __call($name, $arguments){
if( $name=='test' && $this->test_is_public ){
return $this->test();
}else{
throw new LogicException("Method $name() does not exist or is not public\n");
}
}
}
echo "Test should be public:\n";
$numeric = new One('123e20');
$numeric->test();
echo "Test should be private:\n";
$non_numeric = new One('foo');
$non_numeric->test();
I haven't thought about the side effects. Probably, it's only useful as mere proof of concept.

PHP How to call method from extended class

Trying to use objects that extend singletone, but something I can't do.
How to call method from extended class?
How to show 13 non 12 with singleton?
class SingletonTest
{
protected static $_instance;
private function __construct(){}
private function __clone(){}
public static function getInstance() {
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
public function test2(){
return 12;
}
}
class ExtendSingleton extends SingletonTest
{
public function test2() {
return 13;
}
}
$b = ExtendSingleton::getInstance();
echo $b->test2(); //12
You will get what you want if you use static binding keyword "static" instead of "self"
class SingletonTest
{
protected static $_instance;
private function __construct(){}
private function __clone(){}
public static function getInstance() {
if (null === static::$_instance) {
static::$_instance = new static();
}
return static::$_instance;
}
public function test2(){
return 12;
}
}
class ExtendSingleton extends SingletonTest
{
public function test2() {
return 13;
}
}
$b = ExtendSingleton::getInstance();
echo $b->test2(); //13
$a = SingletonTest::getInstance();
echo $a->test2(); //13
exit;
But as You see in the above example this way a class which You will call first to "getInstance" will take place to store its instance in the $_instance field.
There is no way to create a base singleton class and inherit singleton behavior.
public static function getInstance()
{
static $instances = array();
$calledClass = get_called_class();
if (!isset($instances[$calledClass]))
{
$instances[$calledClass] = new $calledClass();
}
return $instances[$calledClass];
}
So this should work for you:
(So first normally functions are public so you can use them if you extend from another class! And the you have to make an object from ExtendSingleton not from SingletonTest since ExtendSingleton exdend's -> SingletonTest and not the other way.)
<?php
class SingletonTest {
protected static $_instance;
public function __construct() {
}
public function __clone() {
}
public static function getInstance() {
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
public function test2(){
return 12;
}
}
class ExtendSingleton extends SingletonTest {
public function test2() {
return 13;
}
}
$b = new ExtendSingleton();
echo $b->test2(); //13
?>
Output:
13
I've tested bicccio's solution and it works
class SingletonTest
{
protected static $_instances = [];
private function __construct(){}
private function __clone(){}
public static function getInstance()
{
$calledClass = get_called_class();
if (!isset(self::$_instances[$calledClass]))
{
self::$_instances[$calledClass] = new $calledClass();
}
return self::$_instances[$calledClass];
}
public function test2(){
return 12;
}
}
class ExtendSingleton extends SingletonTest
{
public function test2() {
return 13;
}
}
$b = ExtendSingleton::getInstance();
echo $b->test2(); //13
$a = SingletonTest::getInstance();
echo $a->test2(); //12
You can extend singleton class in php using late static binding the whole process is well discussed in this question.
Creating the Singleton design pattern in PHP5

Categories