Calling method on all instances of class - php

I am looking for a way to call a function on all instances of a class preferably via a static method call.
Example:
class number{
private $number;
static function addAll(){
//add all of the values from each instance together
}
function __construct($number){
$this->number = $number;
}
}
$one = new number(1);
$five = new number(5);
//Expecting $sum to be 6
$sum = number::addAll();
Any help on this would be greatly appreciated. Thanks!

It can be done like this:
class MyClass {
protected $number;
protected static $instances = array();
public function __construct($number) {
// store a reference of every created object
static::$instances [spl_object_hash($this)]= $this;
$this->number = $number;
}
public function __destruct() {
// don't forget to remove objects if they are destructed
unset(static::$instances [spl_object_hash($this)]);
}
/**
* Returns the number. Not necessary here, just because
* you asked for an object method call in the headline
* question.
*/
public function number() {
return $this->number;
}
/**
* Get's the sum from all instances
*/
public static function sumAll() {
$sum = 0;
// call function for each instance
foreach(static::$instances as $hash => $i) {
$sum += $i->number();
}
return $sum;
}
}

Related

Convert Class Instance to float

Lets say there is this class:
class Number {
private $asString;
private $asFloat;
public function __construct($input) {
$this->asString = $input;
$this->asFloat = $this->parse($input);
}
private function parse($input) {…}
//magic method for $n1 . $n2 operations
public function __toString() { … }
//method for $n1 + $n2 operations
public function __toFloat() { … }
}
Unfortunately the __toFloat() magic method does not exist. Is there any way, other than: $sum = $n1->toFloat() + $n2->toFloat(), without having to call that ->toFloat() method all the time, when the object is used in the context of mathematical operations.
In Javascript on has the ability to create a valueOf() method and I am searching for a way to create something similar in php. Any ideas?
You can use invoke as solution for this case
<?php
class Number
{
private $asString;
private $asFloat;
public function __construct($input)
{
$this->asString = $input;
$this->asFloat = $this->parse($input);
}
public function __invoke()
{
return $this->asFloat;
}
private function parse($input)
{
return (float) $input;
}
public function __toString()
{
return $this->asString;
}
}
$n1 = new Number(5);
$n2 = new Number(3);
var_dump($n1() + $n2());

PHP 7 Arrays - Detection of property of an element of a 2D array

I want my PHP IDE (NuSphere PhpEd) to detect a property of my 2D array element ( an object ) whose property is not showing up after I type a right arrow in my IDE.
Is there any way in PHP 7 to auto generate suggestions of a multidimensional array element properties where each element is an object with certain properties?
<?php
class Cell
{
private $color;
public function __construct()
{
$this->color = "red";
}
public function __get($propertyName)
{
if ($propertyName == 'color')
return $this->color;
}
public function __set($propertyName, $value)
{
if ($propertyName == 'color')
$this->color = $value;
}
}
class Matrix implements ArrayAccess
{
private $matrix = array();
public function __construct($maxX, $maxY)
{
$this->matrix = array_fill(1, $maxX, array_fill(1, $maxY, null));
}
public function &offsetGet($name)
{
return $this->matrix[$name];
}
public function offsetSet($name, $value)
{
$this->matrix[$name] = $value;
}
public function offsetExists($name)
{
return isset($this->matrix[$name]);
}
public function offsetUnset($name)
{
unset($this->matrix[$name]);
}
}
$matrix = new Matrix(3,3);
for ($xIdx = 1; $xIdx <= 3; $xIdx++)
for ($yIdx = 1; $yIdx <= 3; $yIdx++)
$matrix[$xIdx][$yIdx] = new Cell();
$matrix[2][2]->color = "green";
echo $matrix[2][2]->color;
?>
If you're happy to use phpdoc annotations, you can use the Type[][] annotation to declare a variable as being a 2D array of Type. In the case of a class property that looks like:
/** #var Cell[][] */
private $matrix = [];
Or for the return value of a class method:
/**
* #return Cell[][]
*/
public function getMatrix() {
return $this->matrix;
}
In the case of PHPStorm, that provides this:
I tried a workaround in order to force phpdoc to pick up my property or method following the arrow.
Here is what I did.
class Matrix
{
protected $maxX;
protected $maxY;
private $matrix = array();
public function __construct($maxX, $maxY)
{
$this->maxX = $maxX;
$this->maxY = $maxY;
$this->matrix = array_fill(1, $maxX, array_fill(1, $maxY, 0));
return $this;
}
public function getMaxX()
{
return $this->maxX;
}
public function getMaxY()
{
return $this->maxY;
}
public function get($x, $y)
{
if (isset($this->matrix[$x][$y]))
return $this->matrix[$x][$y];
throw new OutOfBoundsException("Array at indices $x, $y is out of bounds!");
}
}
class Main
{
public function __construct()
{
}
public function setArrayVal($x, $y)
{
$cell = new Cell();
//Set Value in some arbitrary method in Main Class
$this->matrix($x, $y)->set($cell);
//Or if $val is public in Cell class
// $this->matrix($x, $y)->val = $cell;
}
//Method of Main Class
public function matrix($x, $y) : Cell //Note Cell here specified for type hinting
{
//Note, matrix below is a property, not method, whose type corresponds to the matrix class
return $this->matrix->set($x, $y);
}
}
class Cell
{
private $val;
public function __construct()
{
}
// Method set in Cell class
public function set($val)
{
$this->val = $val;
}
}

How to pass a chained method as an argument for another method in the same class?

I have a class with a bunch of chained methods. Here is an example:
class Sum {
public static $res = [];
private static $instance = null;
public static function run() {
if (self::$instance === null)
self::$instance = new self;
return self::$instance;
}
public function res() {
return self::$res;
}
public function addTen($int) {
self::$res = $this->addFour($str) + 6;
return $this;
}
public function addFour($int) {
self::$res = $int + 4;
return $this;
}
}
So if I want to call the addTen() method I can do like so:
echo Sum::run()->addFour(5)->res(); // Works, returns 9
echo Sum::run()->addTen(5)->res(); // Doesn't work
The above code doesn't work because the chained methods return the current object from the Sum class. So I managed to fix this by changing the addTen() method so it calls the res() method after the addFour() method like so:
public function addTen($int) {
self::$res = $this->addFour($str)->res() + 6;
return $this;
}
In the above case, that is ok because there is only on method being called from inside the addTen() method but what if I need to call a lot of other chained methods from inside the addTen() method? How can I do so the res() method is no longer needed to be called after every single call from another chained method inside the class (it could become unhandable to have a lot of "->res()" being called everywhere in the class).
I do not know what is your task for this class, but manually writing "add" per function will not make your class adaptable. As I have noted, you have used an array and not chain the $res properly. Since this is a sum class I would expect that you want to sum up the chain.
so I rewrote your class:
<?php
class Sum {
public static $res = [];
private static $instance = null;
public static function run() {
if (self::$instance === null)
self::$instance = new self;
return self::$instance;
}
public function res() {
return array_sum(self::$res);
}
public function add($int) {
self::$res[] = $int;
return $this;
}
}
$sum = new Sum();
$x = $sum->add(5)->add(6)->res();
echo $x; // 11
and you can see it work here:
https://3v4l.org/itDHN

Using php to convert a number to number format with oop methods

If I have a function, e.g. to convert a number to a number format, I obviously want it to take any input var and to return a change to that same input var. However, the below isn't working and I'm not sure why. I understand how to use number_format etc, but I don't get how it fits with OOP:
Class generic{
public function numeric($num){
if(!is_numeric($num) && !is_float($num)){
throw new Exception("Inputed number is not numeric.");
}
//Convert the input to a number format
$this->num = number_format($num,2);
echo $this->num; // shows a number in the new format..
//Return the input with its new value
$num = $this->num;
return $num;
}
}
class someother class {
//function receiving an array and processing the numbers from it.
public function display_info($data) {
foreach($data->listing as $item) {
$price = $price+$item->price;
}
echo $price; //this shows a number in original format.
//Process $price through the generic class 'numeric' function
generic::numeric($price);
echo '<br/>Total:'.$price.'<br/>'; //This also shows the original format
$output = $this->someotherfunction($price);
return $output;
}
public function someotherfunction($data) {
//Manipulate the data
return $data;
}
}
//Create a new display object to process the pre-existing array $data
$test = new someother();
//Process an array containing
$test->display_info($data);
If you can help me to understand this I'd be really grateful.
How does $this->num = $num vs $num = $this->num work?
class Generic {
private $num;
public function __construct($num) {
$this->num = $num;
}
public function numeric() {
if(!is_numeric($this->num) && !is_float($this->num)){
throw new Exception("Inputed number is not numeric.");
}
$this->num = number_format($this->num,2);
return $this;
}
public function value() {
return $this->num;
}
}
class OtherClass {
private static function setNum($num) {
return new Generic($num);
}
public function display_info() {
$price = self::setNum(100);
echo '<br/>Total:'.$price->numeric()->value().'<br/>';
}
}
$test = new OtherClass();
$test->display_info();
If you really want to keep object oriented programming, but I don't think numeric interactions are OOP closed, however what I have done here.
You Generic class holds a number, which you modify bu several method, in this case we have only numeric() method.
In your display method you call this class, and set it the value of the price, II hardcoded 100 but it could be whatever numeric value you want.
As the numeric() method modifies the $this->num from its object, and return its instance you can call value() method which will return the new modified value.
Once you set value to the class
Then you modify it by a method (numeric())
Then you pass the value() to the echo
The output is:
Total:100.00
The example from my comment:
class Generic {
private $num;
private $normalized;
public function __construct($num) {
$this->num = $num;
$this->normalized = $num;
}
public function numeric() {
if(!is_numeric($this->num) && !is_float($this->num)){
throw new Exception("Inputed number is not numeric.");
}
$this->num = number_format($this->num,2);
return $this;
}
public function toInt() {
$this->num = intval($this->num);
return $this;
}
public function printR() {
echo "<pre>".print_r($this->num, true)."</pre>";
}
/**
* As normalized was set to the original value of $num and was not modified,
* you will recieve what you have put from the beginning to the constructor
*/
public function normalize() {
$this->num = $this->normalized;
return $this;
}
/**
* You can use this method to retrieve the original value (without calling normalize())
* And you will still have the modified $num, if you want to use it
*/
public function originalValue() {
return $this->normalized;
}
public function value() {
return $this->num;
}
}
class OtherClass {
private static function setNum($num) {
return new Generic($num);
}
public function display_info() {
$price = self::setNum(100);
/**
* numeric() changes it with number_format()
* <pre>100.00</pre>
*/
$price->numeric()->printR();
/**
* toInt() changes it to integer
* <pre>100</pre>
*/
$price->toInt()->printR();
$price->numeric();
/**
* The original value is still kept
* 100
*/
echo $price->originalValue();
/**
* But the object is changed (because of numeric() call)
* 100.00
*/
echo $price->value();
$price->normalize();
/**
* After being normalized to the original value
* 100
*/
echo $price->value();
}
}
You need to understand scope, and how variables are passed in php.
The function in your generic class is passed a COPY of the price variable - no changes this function makes effects the original price var in the someother object.
To do what you want:
Class generic{
//must be static to be called statically
public static function numeric($num){
if(!is_numeric($num) && !is_float($num)){
throw new Exception("Inputed number is not numeric.");
}
return number_format($num,2);
}
}
class someothere{
//function receiving an array and processing the numbers from it.
public function display_info($data) {
foreach($data->listing as $item) {
$price = $price+$item->price;
}
//the generic::numeric function RETURNS a value, it does NOT modify the original
echo '<br/>Total:'.generic::numeric($price).'<br/>';
}
}
If you did, for some reason, want the function to effect the original price variable, you would need to pass it by reference:
Class generic{
//must be static to be called statically
//notice the & symbol that means that a refernce rather than a copy is passed
public static function numeric(&$num){
if(!is_numeric($num) && !is_float($num)){
throw new Exception("Inputed number is not numeric.");
}
//edits the original variable, no need to return anything
$num = number_format($num,2);
}
}
class someothere{
//function receiving an array and processing the numbers from it.
public function display_info($data) {
foreach($data->listing as $item) {
$price = $price+$item->price;
}
generic::numeric($price);//price is now editied
echo '<br/>Total:'.$price.'<br/>';
}
}

PHP getter/setter to array

Following "problem"
PHP Class with a lot of propertys. A lot of Getters / Setter.
Is there any nice solution to convert all propertys to an array?
protected $name;
protected $date;
public function getName();
public function getDate();
public function asArray(); // call all getters?
Is your API already defined and are you stuck with getX and setX methods? I much prefer properties. Less typing, better distinction between properties and methods, and resulting code looks more like PHP and less like Java. But exposing properties doesn't mean you lose encapsulation and make all your internals public. With __get and __set magic methods you can have pretty fine-grained control over what you present. Plus, it would be rather trivial to dump the properties as an array:
class Foo
{
protected $properties;
public function __construct() {
$this->properties = array();
}
public function __set($prop, $value) {
$this->properties[$prop] = $value;
}
public function __get($prop) {
return $this->properties[$prop];
}
public function toArray() {
return $this->properties;
}
}
Alas, if you're stuck with setters/getters because of a cranky boss or some misunderstanding of what OOP must be, why not just cast the object to an array?
class Bar
{
public $x;
public $y;
public $z;
protected $a;
protected $b;
protected $c;
private $q;
private $r;
private $s;
public function __construct() {
}
public function setA($value) {
$this->a = $value;
}
public function getA() {
return $this->a;
}
public function setB($value) {
$this->b = $value;
}
public function getB() {
return $this->b;
}
public function setC($value) {
$this->c = $value;
}
public function getC() {
return $this->c;
}
public function toArray() {
return (array)$this;
}
}
Notice how public, protected, and private properties are cast:
$bar = new Bar();
print_r($bar->toArray());
array(9) {
["x"]=>
NULL
["y"]=>
NULL
["z"]=>
NULL
[" * a"]=>
NULL
[" * b"]=>
NULL
[" * c"]=>
NULL
[" Foo q"]=>
NULL
[" Foo r"]=>
NULL
[" Foo s"]=>
NULL
}
Note that the array keys for protected/private don't start with a space, it's a null. You can re-key them, or even filter out protected/private properties if you like:
public function toArray() {
$props = array();
foreach ((array)$this as $key => $value) {
if ($key[0] != "\0") {
$props[$key] = $value;
}
}
return $props;
}
You're working with a dynamic language; take advantage of that and enjoy it!
How about using ReflectionClass and ReflectionMethod, something like this:
class PropertyHolder
{
private $name;
private $date;
private $anotherProperty;
public function __construct($name, $date)
{
$this->name = $name;
$this->date = $date;
}
public function getName()
{
return $this->name;
}
public function getDate()
{
return $this->date;
}
public function asArray()
{
$result = array();
$clazz = new ReflectionClass(__CLASS__);
foreach ($clazz->getMethods() as $method) {
if (substr($method->name, 0, 3) == 'get') {
$propName = strtolower(substr($method->name, 3, 1)) . substr($method->name, 4);
$result[$propName] = $method->invoke($this);
}
}
return $result;
}
You could use PHP's reflection capabilities. Here's an example:
http://www.weberdev.com/get_example-4672.html
Try looking into get_object_vars(), get_class_vars and others in the same category. The examples shown there look like pretty much what you need. Check the comments there (for example http://www.php.net/manual/en/function.get-class-vars.php#87772) they already provide ways that suit your needs.
A simple (array) cast on $this will suffice:
(array) $this;
If you have additional properties (private ones for example, that shall not be toArray()ed) you can afterwards unset these:
public function toArray() {
$array = (array) $this;
unset($array['private'], $array['privateagain']);
return $array;
}
One option would be to create an array in your constructor.
You will have one getter and one setter..
When you want to set or get something, do something like:
$foo->get( 'UID' ); //(to get user id)
or
$foo->set( 'UID', 5 ); // to set something)

Categories