Accessing object properties within a callback execution - php

Let's say I have the following code:
class RandomNumber{
public $number;
function __construct($range,$callback){
$this->number = rand(0,$range);
$callback();
}
}
$rnd = new RandomNumber(9,function(){
echo "Line 11: ".$rnd->number."\n"; // Not working: empty variable
echo "Line 12: ".$number."\n"; // Not working: empty variable
echo "Line 13: ".$this->number."\n"; // Not working: Fatal error: Using $this when not in object context on line 13
});
echo "Line 15: ".$rnd->number."\n"; // Working: echoed random number
So I'm trying to access the property (number) of the newly created object. And I can not guess how to do it properly. I have read some PHP documentation and tried to search Google for the solution but I missed the thing or I used wrong keywords for searching. I'd be happy if you will point me into the right direction.

It's barely possible, because the things are happening one after the another, as well as the function is not aware of the outside world. In your case $rnd is declared outside the function as well as it's not already initialized (it will be after the whole line is executed)
And yes, you are not able to use $this, but you can pass $this in order to inject the newly created object.
class RandomNumber{
public $number;
function __construct($range,$callback){
$this->number = rand(0,$range);
$callback($this);
}
}
$rnd = new RandomNumber(9,function($obj){
echo "Line 11: ".$obj->number."\n";
});

You define the function outside of the scope of the class, inside of it it works just fine.
And $rnd cant work inside of it, as it is not yet filled, this will happen after the constructor did its work.
This works:
class RandomNumber{
public $number;
function __construct($range,$callback){
$this->number = rand(0,$range);
$callback($this);
$call2 = function(){
echo "Line 7 : " .$this->number."\n"; // Works
};
$call2();
}
public function callback($callback){
$callback();
}
}
$rnd = new RandomNumber(9,function($rnd){
echo "Line 15: ".$rnd->number."\n"; // Works
});
$rnd->callback(function() use ($rnd) {
echo "Line 19: ".$rnd->number."\n"; // Works
});

Related

PHP returns object as null occasionally and unintentionally

We have PHP code in production that sometimes fails with "Call to member function on null", although the same code path executes fine several times before that in one invocation. We have a test that reproduces the error consistently at the same run of the loop.
I already proved that the object gets created correctly in the factory even if it gets returned as null. The factory method must not return null in any case, as indicated in the DocBlock. This question is not related to nullable return types or something like that.
The process does not exceed memory or runtime limitations and I already tried turning off the garbage collector, but no luck. The error happens both in PHP 7.0 and 7.3 on Debian, did not try on other versions or operating systems.
I am not allowed to paste the real code here, but I wrote a simple mockup to explain in more detail. Please keep in mind that this demo code will not result in the error, it is just meant to show the general structure of the program that runs into this fault.
// Three placeholder classes with common methods
class Bender
{
public function common()
{
echo "Bend, bend!" . PHP_EOL;
}
}
class Clamper
{
public function common()
{
echo "Clamp, clamp!" . PHP_EOL;
}
}
class Worker
{
public function common()
{
echo "Work, work!" . PHP_EOL;
}
}
// abstract class with static factory to produce objects
abstract class MomCorp
{
/**
* Factory to create one of several objects
*
* #param string $name
* #return Bender|Clamper|Worker
*/
public static function factory($name)
{
$type = self::managementDecision($name);
switch ($type)
{
case "bender":
$robot = new Bender();
break;
case "clamper":
$robot = new Clamper();
break;
default:
$robot = new Worker();
}
// optional QA works flawlessly here, object is fine all the time!
// $robot->common();
return $robot;
}
public static function managementDecision($name)
{
// irrelevant magic happens on $name here
return "bender";
}
}
foreach (['Rodriguez', 'Angle-ine', 'Flexo', 'Billie'] as $newName)
{
echo "$newName: ";
// The next two lines break after some loops - why?
// The perfectly functional object in factory gets returned as null
$bot = MomCorp::factory($newName);
$bot->common();
}
// SAMPLE OUTPUT
// Rodriguez: Bend, bend!
// Angle-ine: Bend, bend!
// Flexo: Bend, bend!
// Billie: Call to a member function common() on null
Has anyone experienced the same and has any hints on what might cause such an error and how to fix it?

Undefined Variable within class

I recently made a class in PHP
I am trying to declare a variable within class and using str_replace in a function but its show undefined variable
class Status{
$words = array(".com",".net",".co.uk",".tk","co.cc");
$replace = " ";
function getRoomName($roomlink)
{
echo str_replace($words,$replace,$roomlink);
}
}
$status = new Status;
echo $status->getRoomName("http://darsekarbala.com/azadari/");
Any kind of help would be appreciated thanks you
Your variables in the function getRoomname() aren't adressed properly. Your syntax assumes the variables are either declared within the function or passed while calling the function (which they aren't).
To do this within a class, do it while using $this->, like this:
function getRoomName($roomlink)
{
echo str_replace($this->words,$this->replace,$roomlink);
}
For further informations, please have a look into this page of the manual.
Maybe because of the version or something, when I tested your exact code, I got syntax error, unexpected '$words' (T_VARIABLE), expecting function (T_FUNCTION), so setting your variables to private or public should fix this one.
About the undefined varible, you have to use $this-> to access them from your class. Take a look:
class Status{
private $words = array(".com",".net",".co.uk",".tk","co.cc"); // changed
private $replace = " "; // changed
function getRoomName($roomlink){
echo str_replace($this->words, $this->replace, $roomlink); // changed
}
}
$status = new Status;
echo $status->getRoomName("http://darsekarbala.com/azadari/");
Also, since getRoomName isn't returning anything, echoing it doesn't do much. You could just:$status->getRoomName("http://darsekarbala.com/azadari/");.
or change to :
return str_replace($this->words, $this->replace, $roomlink);

creating multiple instances of splFileObject

I have a class similar to this
class x {
function __construct($file){
$this->readData = new splFileObject($file);
}
function a (){
//do something with $this->readData;
}
function b(){
//do something with $this->readData;
}
}
$o = new x('example.txt');
echo $o->a(); //this works
echo $o->b(); //this does not work.
it seems if which ever method called first only works, if they are called together only the first method that is called will work. I think the problem is tied to my lack of understand how the new object gets constructed.
The construct is loaded into the instance of the class. And you're instantiating it only once. And accessing twice. Are different actions. If you want to read the file is always taken, should create a method that reads this file, and within all other trigger this method.
I tested your code and it worked normal. I believe it should look at the logs and see if any error appears. If the file does not exist your code will stop.
Find for this error in your apache logs:
PHP Fatal error: Uncaught exception 'RuntimeException' with message 'SplFileObject::__construct(example.txt): failed to open stream
Answering your comment, this can be a way:
<?php
class x {
private $defaultFile = "example.txt";
private function readDefaultFile(){
$file = $this->defaultFile;
return new splFileObject($file);
}
function a (){
$content = $this->readDefaultFile();
return $content ;
}
function b(){
$content = $this->readDefaultFile();
return $content ;
}
}
$o = new x();
echo $o->a();
echo $o->b();
Both methods will return an object splFile.

'Call to undefined function' - Trying to call function from an included file

So I have two files, 'header.php' and 'pluginfile.php'
The function that I want to call resides in 'pluginfile.php' and is:
public function getNonSubscriptionAmount() {
$total = 0;
foreach($this->_items as $item) {
if(!$item->isSubscription()) {
$total += $item->getProductPrice() * $item->getQuantity();
}
else {
// item is subscription
$basePrice = $item->getBaseProductPrice();
Cart66Common::log('[' . basename(__FILE__) . ' - line ' . __LINE__ . "] Item is a subscription with base price $basePrice");
$total += $basePrice;
}
}
return $total;
}
So in 'header.php' I have:
<?php
include_once($_SERVER['DOCUMENT_ROOT']."/wp-content/plugins/plugin-name/folder/PluginFile.php");
print getNonSubscriptionAmount();
?>
This gives the following error when any page is loaded:
Fatal error: Call to undefined function getnonsubscriptionamount() in
/home/username/domain.com/wp-content/themes/theme/header.php on
line 72
I've spent a couple of hours now trying to figure this out alone and am getting nowhere! Any help much appreciated!
#Wiseguy looks like he had the right idea put in the comments.
You are declaring a method and not a function. Is the function the entirety of your plugin.php file or is there more? If it is everything, remove the public modifier and just declare
function getNonSubscriptionAmount() {
// code here
}
But from the looks of the code it is part of a larger class. If thats the case then #Wiseguy comment is right on, you need to instantiate a new object of the class in plugin.php and then the desired method.
$obj = new PluginClass();
$obj->getNonSubscriptionAmount();
You said:
The function that I want to call resides in 'plugin.php' and is:
And in your file you are including:
So in 'header.php' I have:
include_once($_SERVER['DOCUMENT_ROOT']."/wp-content/plugins/plugin-name/folder/PluginFile.php");
print getNonSubscriptionAmount();
You are not including 'plugin.php' which is were the function lives.
Header.php should include 'plugin.php', not 'PluginFile.php'.

PHP: Problems using Singleton pattern and understanding __clone method

I am trying to implement the singleton pattern in php like described here in Example #2:
http://www.php.net/singleton
When I run the example code
$singleton = Example::singleton(); // prints "Creating new instance."
echo $singleton->increment(); // 0
echo $singleton->increment(); // 1
$singleton = Example::singleton(); // reuses existing instance now
echo $singleton->increment(); // 2
echo $singleton->increment(); // 3
it allways ends with Fatal Error 'Clone is not allowed.' directly after 'Creating new instance.'
I would expect that there is no reason for php to call the __clone-method.
In another real-life project of mine I want to have a singleton PlayerManager that holds Player-objects in an array (loaded only once in __construct) and has functions like GetPlayers() or GetPlayersByID($id).
In my script I write something like
$pm = PlayerManager::GetInstance();
$p1 = $pm->GetPlayerByID(0);
echo $p1->SomeNumber; //100
$p1->SomeNumber = 200;
$p2 = $pm->GetPlayerByID(0);
echo $p2->SomeNumber; //100 and not 200, as I would expect
Can someome give me some hints how to implement the PlayerManager using the Singleton pattern correct? I'm not sure if it is only a problem with the singleton or also a problem with returning object references...
I'm not quiet sure why you're getting that error (post your singleton class if you want help with that). Though I always preferred this version to the one you're using, it's a bit simpler: http://www.talkphp.com/advanced-php-programming/1304-how-use-singleton-design-pattern.html
So with the above, your code would look like:
class Counter
{
$CurrentValue = 0;
// Store the single instance of Database
private static $m_pInstance;
private function __construct() { }
public static function getInstance()
{
if (!self::$m_pInstance)
{
self::$m_pInstance = new Counter();
}
return self::$m_pInstance;
}
public function increment ($by)
{
$this->CurrentValue += $by;
return $this->CurrentValue;
}
public function getValue ()
{
return $this->CurrentValue;
}
}
And to use:
$counter = Counter::getInstance();
echo $counter->increment(); // 0
echo $counter->increment(); // 1
$counter = null;
$counter = Counter::getInstance(); // reuses existing instance now
echo $counter->increment(); // 2
echo $counter->increment(); // 3
Tell me how that works out for you.

Categories