Function returning reference to object property - php

I've got an event object that looks like this:
class InputEvent
{
protected $input;
public function __construct(&$input)
{
$this->input = &$input;
}
public function getInput()
{
return $this->input;
}
}
Now, since $input is a string, I have to pass it in by reference. However, when I create an event listener, input value doesn't get changed since getInput function returns $input value rather than reference to $input property.
class Listener
{
public function myEvent(InputEvent $event)
{
$input = $event->getInput();
// doesn't change InputEvent::input property
$input = "asd";
}
}
Is there a way for me to return reference to $input value, so that it gets changed inside event object?
I can make two workarounds, but both are.....well, workarounds, not really pretty.
Wrap $input into a class, for example creating a String class which would only hold value and getter, setter methods.
Add setInput method to InputEvent, but still isn't as elegant as just assigning it to a value like in Listener example above.

As moonwave99 mentioned above, you'll need to use a setter. In your InputEvent class add the method:
public function setInput(&$s) {
$this->input = $s;
}
Or you could return a reference:
public function &getInputRef() {
return $this->input;
}
$input = &$event->getInputRef();
Which I think should work the same.

Have your getInput function return by reference
function &getInput()
^-- signifies return value by reference

class InputEvent
{
protected $input;
public function __construct(&$input)
{
$this->input = $input;
}
public function &getInput()
{
return $this->input;
}
}
$string = "abc";
$a = new InputEvent($string);
$input = &$a->getInput();
$input .= "def";
echo $a->getInput();

Related

When to use method vs setting a property in the constructor?

I'm new to OOP, and I'm not sure when I should be setting properties in the constructor for my own convenience, as opposed to just using a method.
Option 1 (method):
class String {
function __construct($word) {
$this->word = $word;
}
function reverse() {
return str_reverse($this->word);
}
}
Then I can get the reverse like this:
$word = new String('potato');
echo $word->reverse();
Option 2 (property):
class String {
public $reverse;
function __construct($word) {
$this->word = $word;
$this->reverse = $this->reverse();
}
function reverse() {
return str_reverse($this->word);
}
}
Then I can get the reverse like this:
$word = new String('potato');
echo $word->reverse;
The second option looks nicer.
However, I was wondering if there are any pitfalls of using Option 2 all the time?
tl;dr
You need to find out for yourself what works best for your context.
Value Object
Here's an example of a value object that might make sense to you:
it holds state
it is immutable
invoking $word->reverse() returns a new instance of a value object, however, with the reversed string value
final class Word
{
private $word;
public function __construct(string $word)
{
$this->word = $word;
}
public function reverse(): self
{
return new self(strrev($this->word));
}
public function __toString()
{
return $this->word;
}
}
$word = new Word('potato');
echo $word->reverse();
For an example, see:
https://3v4l.org/ONklH
Service
Here's an example of a service:
it doesn't hold any state
invoking $service->reverse() requires passing in the word, it returns the word reversed
final class Service
{
public function reverse(string $word): string
{
return strrev($word);
}
}
$service = new Service();
echo $service->reverse('potato');
For an example, see:
https://3v4l.org/cKECo
Suggested Reading
http://wiki.c2.com/?ValueObject
https://en.wikipedia.org/wiki/Value_object
https://martinfowler.com/bliki/EvansClassification.html

PHP Last Object of Method Chaining

In PHP using method chaining how would one go about supplying a functional call after the last method being called in the chain?
Also while using the same instance (see below). This would kill the idea of implementing a destructor.
The end result is a return value and functional call of private "insert()" from the defined chain properties (of course) without having to call it publicly, no matter of the order.
Note, if I echo (__toString) the methods together it would retrieve the final generated unique code which is normal behavior of casting a string.
Example below:
class object
{
private $data;
function __construct($name) {
// ... some other code stuff
}
private function fc($num) {
// some wicked code here
}
public function green($num) {
$this->data .= fc($num*10);
return $this;
}
public function red($num) {
$this->data .= fc($num*25);
return $this;
}
public function blue($num) {
$this->data .= fc($num*1);
return $this;
}
// how to get this baby to fire ?
private function insert() {
// inserting
file_put_content('test_code.txt', $this->data);
}
}
$tss = new object('index_elements');
$tss->blue(100)->green(200)->red(100); // chain 1
$tss->green(0)->red(100)->blue(0); // chain 2
$tss->blue(10)->red(80)->blue(10)->green(0); // chain 3
Chain 1, 2, and 3 would generated an unique code given all the values from the methods and supply an action, e.g. automatically inserting in DB or creating a file (used in this example).
As you can see no string setting or casting or echoing is taking place.
You could keep a list of things that needs to be initialised and whether they
have been so in this instance or not. Then check the list each time you use
one of the initialisation methods. Something like:
class O {
private $init = array
( 'red' => false
, 'green' => false
, 'blue' => false
);
private function isInit() {
$fin = true;
foreach($this->init as $in) {
$fin = $fin && $in;
}
return $fin;
}
public function green($n) {
$this->init['green'] = true;
if($this->isInit()) {
$this->insert();
}
}
public function red($n) {
$this->init['red'] = true;
if($this->isInit()) {
$this->insert();
}
}
public function blue($n) {
$this->init['blue'] = true;
if($this->isInit()) {
$this->insert();
}
}
private function insert() {
echo "whee\n";
}
}
But personally I think this would be more hassle then it's worth. Better imo
to expose your insert method and let the user of you code tell when the
initialisation is finished. So something that should be used like:
$o->red(1)->green(2)->blue(0)->insert();
-update-
If it's the case that it's impossible to predict what functions need to be called
you really do need to be explicit about it. I can't see a way around that. The reason
is that php really can't tell the difference between
$o1 = new A();
$o2 = $o1->stuff();
and
$o2 = (new A())->stuff();
In a language that allows overloading = I guess it would be possible but really
really confusing and generally not a good idea.
It is possible to move the explicit part so that it's not at the end of the call
chain, but I'm not sure if that would make you happier? It would also go against
your desire to not use another instance. It could look something like this:
class O {
public function __construct(InitO $ini) {
// Do stuff
echo "Whee\n";
}
}
class InitO {
public function red($n) {
return $this;
}
public function green($n) {
return $this;
}
public function blue($n) {
return $this;
}
}
$o = new O((new InitO())->red(10)->red(9)->green(7));
You can of course use just one instance by using some other way of wrapping
but the only ways I can think of right now would look a lot uglier.
Im with PeeHaa, this makes no sense! :)
Only chance to have something magically happen after the last chain was used (without being able to look into the future) is a Destructor/Shutdown function OR a manually cast/call to insert()
You can also decide to implement this statically without using objects.
<?php
class Object
{
private static $data;
public static function set($name)
{
// ... some other code stuff
}
private static function fc($num)
{
// some wicked code here
}
public static function green($num)
{
self::$data .= self::fc($num*10);
return new static;
}
public static function red($num)
{
self::$data .= self::fc($num*25);
return new static;
}
public static function blue($num) {
self::$data .= self::fc($num*1);
return new static;
}
// how to get this baby to fire ?
public static function insert()
{
// inserting
file_put_content('test_code.txt', self::$data);
}
}
//$tss = new object('index_elements');
$Object::set('index_elements')->blue(100)->green(200)->red(100)->insert(); // chain 1
$Object::set('index_elements')->green(0)->red(100)->blue(0)->insert(); // chain 2
$Object::set('index_elements')->blue(10)->red(80)->blue(10)->green(0)->insert(); // chain 3
?>
Ok let's see a code example
<?php
// map dummy class
class map
{
// __call magic method
public function __call($name, $args)
{
return $this;
}
}
// now we chain
$map = new map;
// let's find me
$map->start('here')
->go('right')
->then()
->turn('left')
->and('get water')
->dontEat()
->keep('going')
->youShouldSeeMe('smiling');
here we don't know what the last method would be and we need to trigger a kinda operation or event once we hit the end.
According to data structure we can call this the LIFO stack. (Last in first out)
so how did i solve this on PHP?
// i did some back tracing
... back to the __call function
function __call($name, $args)
{
$trace = debug_backtrace()[0];
$line = $trace['line'];
$file = $trace['file'];
$trace = null;
$getFile = file($file);
$file = null;
$getLine = trim($getFile[$line-1]);
$line = null;
$getFile = null;
$split = preg_split("/(->)($name)/", $getLine);
$getLine = null;
if (!preg_match('/[)](->)(\S)/', $split[1]) && preg_match('/[;]$/', $split[1]))
{
// last method called.
var_dump($name); // outputs: youShouldSeeMe
}
$split = null;
return $this;
}
And whoolla we can call anything once we hit the bottom.
*(Notice i use null once i am done with a variable, i come from C family where we manage memory ourselves)
Hope it helps you one way or the other.

How to control json_encode behavior?

Is there any way to control json_encode behavior on objects? Like excluding empty arrays, null fields and so on?
I mean something like when using serialize(), where you can implement magic __sleep() method and specify what properties should be serialized:
class MyClass
{
public $yes = "I should be encoded/serialized!";
public $empty = array(); // // Do not encode me!
public $null = null; // Do not encode me!
public function __sleep() { return array('yes'); }
}
$obj = new MyClass();
var_dump(json_encode($obj));
The most correct solution is extending the interface JsonSerializable;
by using this interface you just need to return with the function jsonSerialize() what you want json_encode to encode instead of your class.
Using your example:
class MyClass implements JsonSerializable{
public $yes = "I should be encoded/serialized!";
public $empty = array(); // // Do not encode me!
public $null = null; // Do not encode me!
function jsonSerialize() {
return Array('yes'=>$this->yes);// Encode this array instead of the current element
}
public function __sleep() { return array('yes'); }//this works with serialize()
}
$obj = new MyClass();
echo json_encode($obj); //This should return {yes:"I should be encoded/serialized!"}
Note: this works in php >= 5.4 http://php.net/manual/en/class.jsonserializable.php
You could make the variables private. Then they won't show up in the JSON encoding.
If that is not an option, you could make a private array, and use the magic methods __get($key) and __set($key,$value) to set and get values in/from this array. In your case the keys would be 'empty' and 'null'. You can then still access them publicly but the JSON encoder will not find them.
class A
{
public $yes = "...";
private $privateVars = array();
public function __get($key)
{
if (array_key_exists($key, $this->privateVars))
return $this->privateVars[$key];
return null;
}
public function __set($key, $value)
{
$this->privateVars[$key] = $value;
}
}
http://www.php.net/manual/en/language.oop5.overloading.php#object.get

Trying to pass a an array_map inside a class. Its returning null.

I have a class with 2 functions. One function has the array map that pass the array to another function within the same class. Unfortunatly the array is dumped as NULL. Any fix?
class filter
{
public function filt($value)
{
$value = mysql_escape_string($value);
$value = trim($value);
return $value;
}
public function passover($variables)
{
$variables = array_map("filt",$variables);
return $variables;
}
}
$filter = new filter();
$m= $filter->passover($arr =array('smith'=>1, 'smith'=>2));
var_dump($m);
To provide an object method as callback, you need a different syntax:
array_map(array($this, 'filt'), $variables)
http://php.net/manual/en/language.types.callable.php

PHP Chaining... I just can't get it!

I'm trying to create a chaining function for working with strings that are returned from an XML file.
1 original string may have multiple replacements, some of which come from the XML file.
Here is the ugly and standard wrapped approach:
str_replace("what","is meant", str_replace("name","randomer",str_replace("blah", "hello", $string1)));
Here is the approach I'm trying to replicate (like Java):
$string1.replace("blah","hello").replace("name","randomer").replace("what","is meant");
With the above, it works easily... until I use the XML function to get the replacing string.
Here's my class:
class resources{
private static $instance, $string;
public static function getString($stringName){
# Create new instance
self::$instance = new self;
# Grabs stringName from an XML file
self::$string = $stringName;
# Return instance
var_dump(self::$instance);
return self::$instance;
}
public static function replace($replace_this, $with_this){
# Replace and return instance
self::$string = str_replace($replace_this, $with_this, self::$string);
return self::$instance;
}
public static function show(){
# Return String
return self::$string;
}
}
echo resources::getString("alpha") // alpha
->replace("lpha","bravo") // abravo
->replace("vo", resources::getString("charlie")->show()) // should be abracharlie
->show(); // charlie
I'd like it to understand why it's not working as I think it should and how it should actually work.
It seems that when I call the class again (despite var_dump saying its a seperate instance), it replaces the original text with "charlie" so I can't just replace a part of the first bit.
Thanks, Dominic
EDIT: Yes!! I have figured it out (using statics) but it seems Ryano below has an even better solution
<?php
class resources{
private static $instance, $string, $originalString;
public static function getInstance($stringName){
self::$instance = new self();
self::$originalString = $stringName;
return self::$instance;
}
public static function getString($stringName){
# Grabs stringName from an XML file
self::$string = $stringName;
return self::$instance;
}
function replace($replace_this, $with_this){
self::$originalString = str_replace($replace_this, $with_this, self::$originalString);
self::$string = self::$originalString;
return self::$instance;
}
function show(){
return self::$string;
}
}
echo resources::getInstance("alpha") // alpha
->replace("lpha","bravo") // abravo
->replace("vo", resources::getString("charlie")->show()) // should be abracharlie
->replace("lie", resources::getString("vo")->show()) // abracharvo
->show(); // abracharvo
echo "<br />";
echo resources::getInstance("randomer") // randomer
->replace("er","") // random
->replace("ran", resources::getString("")->show()) // dom
->replace("dom", resources::getString("Dom")->show()) // Dom
->show(); // Dom
echo "<br />";
echo resources::getInstance("nomster") // nomster
->replace("nom","nmo") // nmoster
->replace("nom", resources::getString("mon")->show()) // nmoster
->replace("nmo", resources::getString("mon")->show()) // monster
->show(); // monster
?>
Your problem is that everything is static. I would suggest brushing up on some object-oriented programming fundamentals.
Because everything is static, the state is shared between all invocations of the functions. In the line replace("vo", resources::getString("charlie")->show()), the nested call to resources::getString replaces the string built so far (abravo) with the argument to getString which is charlie. Then the wrapping function is called like replace("vo", "charlie"), but the value of self::$string is now charlie, which does not contain vo and therefore the final show() then returns simply charlie. If, instead of vo, you'd called it with replace("ar", resources::getString("charlie")->show()), the final show() would have instead returned chcharlielie.
You must create a class with non-static member variables and methods in order to maintain separate states.
Here's a working version:
class resources {
private $string;
public function __construct ($string) {
$this->string = $string;
}
public static function getString ($string) {
$obj = new resources($string);
return $obj;
}
public function replace ($replace_this, $with_this) {
# Replace and return instance
$this->string = str_replace($replace_this, $with_this, $this->string);
return $this;
}
public function show () {
# Return String
return $this->string;
}
}
Edit: I like the above code as the closest transition from the question's code. If I was writing something similar myself, I would simplify it further like this:
class Str {
private $str;
private function __construct ($str) {
$this->str = $str;
}
public static function with ($str) {
return new Str($str);
}
public function replace($replace_this, $with_this) {
$this->str = str_replace($replace_this, $with_this, $this->str);
return $this;
}
public function __toString () {
return $this->str;
}
}
echo Str::with('nomster')->replace('nom', 'mon') . "\n";
Now there's no need for show() and the names are a little nicer to type. Many other useful methods could be added here; any php string function you would want to chain.
When you call getString() several times, you create several instances since you call new self() in getString().
To prevent that from happening you should create a method getInstance() and use that in getString()
public static function getInstance() {
if(!self::instance) {
self::instance = new self();
}
return self::instance;
}
public static function getString() {
$instance = self::getInstance();
// use $instance here instead of self::instance
}

Categories