I'm not sure how name this but I have already seen in C# something like:
decimal value = 12.01;
print obj->getAmount() // 1002.01
print obj->getAmount()->format('...'); // 1.002,01
So, On PHP I tried something like:
class Account {
public function getAmount() {
return new Decimal($this->_amount);
}
}
class Decimal {
private $_value;
public function __construct($value) {
$this->_value = $value;
return (float) $this->_value;
}
public function format() {
return number_format($this->_value, 2, ',', '.');
}
}
Where was possible get the value in two ways:
$account->getAmount() // 1002.01
$account->getAmount()->format() // 1.002,01
But, if this is possible I would say that something is missing and I'm not sure how to do.
PHP can't convert objects to floats or ints, only to strings. This can be used for display purposes:
class Account {
public function __construct($amount) {
$this->_amount = $amount;
}
public function getAmount() {
return new Decimal($this->_amount);
}
}
class Decimal {
private $_value;
public function __construct($value) {
$this->_value = $value;
}
public function __toString() {
return strval($this->_value);
}
public function format() {
return number_format($this->_value, 2, ',', '.');
}
}
$account = new Account(1002.01);
echo $account->getAmount(), "\n"; // 1002.01
echo $account->getAmount()->format(), "\n"; // 1.002,01
but don't attempt to do anything else with that:
echo $account->getAmount() + 42; // 'Object of class Decimal could not be converted to int'
In Account class you need to announce $ammount variable
Remove underscore in variable names
And you need to create object before creating its methods.
Related
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/>';
}
}
This question already has an answer here:
Overloading method of comparison for custom class
(1 answer)
Closed 9 years ago.
I was wondering if there is a way to create a class in PHP that when compared with other variables a default value is used instead of the class itself? such that:
class Test {
private $name;
private $val;
public function __construct($name, $val) {
$this->name = $name;
$this->val = $val;
}
public __default() {
return $val;
}
public function getName() {
return $name;
}
}
then I could use a function like __default when I compare it to another value such as:
$t = new Test("Joe", 12345);
if($t == 12345) { echo "I want this to work"; }
the phrase "I want this to work" will print.
As far as I know this is not possible. The closest thing you're looking for is the __toString() method to be set on the class.
http://php.net/manual/en/language.oop5.magic.php
PHP might try to convert it to an Integer, but I'm not sure if there are class methods to accomplish this. You could try string comparison.
<?php
class Test {
private $name;
private $val;
public function __construct($name, $val) {
$this->name = $name;
$this->val = $val;
}
public function __toString() {
return (string)$this->val;
}
public function __toInt() {
return $this->val;
}
public function getName() {
return $this->name;
}
}
$t = new Test("Joe", 12345);
if($t == '12345') { echo "I want this to work"; }
The __toString magic method will do what you want with some caveats:
class Test {
private $name;
private $val;
public function __construct($name, $val) {
$this->name = $name;
$this->val = $val;
}
public function __toString() {
return $this->val;
}
public function getName() {
return $this->name;
}
}
Objects can't be directly cast to an integer so will always get a when comparing to an integer but if you cast either side of the comparison to a string it will work as expected.
if($t == 12345) // false with a warning about can't cast object to integer
if((string)$t == 12345) // true
if($t == "12345") // true
Implement __toString() in your class.
Like:
class myClass {
// your stuff
public function __toString() {
return "something, or a member property....";
}
}
Your object will unlikely equals integer. But you can implement something similar to Java's hashCode() - a class method that do some math to produce numeric hash - a return value based on i.e. its internal state, variables etc. Then compare these hash codes.
Why not something along this line:
class Test {
private $name;
private $val;
public function __construct($name, $val) {
$this->name = $name;
$this->val = $val;
}
public __default() {
return $val;
}
public compare($input) {
if($this->val == $input)
return TRUE;
return FALSE;
}
public function getName() {
return $name;
}
}
$t = new Test("Joe", 12345);
if($t->compare(12345)) { echo "I want this to work"; }
From other answers it appears there is not a built in function to handle this.
Most of the work I do is on a legacy app written procedurally. I'm beginning to convert pieces of it to OOP, and came across this example class used to add multiple times together:
At the bottom of the class, there is a public function called __toString(), which appears to return some formatted text.
class Duration
{
/*
$d1 = Duration::fromString('2:22');
$d1->add(Duration::fromString('3:33'));
echo $d1; // should print 5:55
*/
public static function fromString($string)
{
$parts = explode(':', $string);
$object = new self();
if (count($parts) === 2) {
$object->minutes = $parts[0];
$object->seconds = $parts[1];
} elseif (count($parts) === 3) {
$object->hours = $parts[0];
$object->minutes = $parts[1];
$object->seconds = $parts[2];
} else {
// handle error
}
return $object;
}
private $hours;
private $minutes;
private $seconds;
public function getHours() {
return $this->hours;
}
public function getMinutes() {
return $this->minutes;
}
public function getSeconds() {
return $this->seconds;
}
public function add(Duration $d) {
$this->hours += $d->hours;
$this->minutes += $d->minutes;
$this->seconds += $d->seconds;
while ($this->seconds >= 60) {
$this->seconds -= 60;
$this->minutes++;
}
while ($this->minutes >= 60) {
$this->minutes -= 60;
$this->hours++;
}
}
public function __toString() {
return implode(':', array($this->hours, $this->minutes, $this->seconds));
}
}
The public static function fromString() contains a return, and is how the class is called from a script. How does this class use __toString? Why isn't the implode simply included in fromString()?
Straight from the documentationPHP.net:
The __toString() method allows a class to decide how it will react
when it is treated like a string. For example, what echo $obj; will
print. This method must return a string, as otherwise a fatal
E_RECOVERABLE_ERROR level error is emitted.
The class itself doesn't use __toString(), it's only mentioned implicitly in the usage suggestion in the comment: echo $d1; // should print 5:55
Whenever you treat an object as a string, PHP will replace $obj with $obj.__toString() for you.
This happens when:
echo-ing
using printf with %s
casting to string: (string) $obj
concatenating with .
This isn't an exhaustive list of course. If you treat an object as a string that doesn't have a __toString method, you get:
Catchable fatal error: Object of class * could not be converted to string in
Basically, the one makes Duration objects from strings, the other turns Duration objects into strings.
This will return an object of class Duration, made from string $string:
public static function fromString($string) { ... store input string ... }
If you now want to output the original string, you can't just echo the Duration object itself, because it is not a string but a Duration object.
If you want to be able to echo a Duration object, you implement the __toString() function:
public function __toString() { ... build and return output string ... }
And then you can do stuff like this:
$stringOne = 'Some string';
$durationObject = Duration::fromString($stringOne);
echo $durationObject; // Echo-ing the object works because __toString is implemented.
The third line in that code won't work if you don't implement the __toString() method.
It is a magic method as you can read in the documentation. Example #2:
<?php
// Declare a simple class
class TestClass
{
public $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
public function __toString()
{
return $this->foo;
}
}
$class = new TestClass('Hello');
echo $class; // Hello
If I have the following class example:
<?php
class Person
{
private $prefix;
private $givenName;
private $familyName;
private $suffix;
public function setPrefix($prefix)
{
$this->prefix = $prefix;
}
public function getPrefix()
{
return $this->prefix;
}
public function setGivenName($gn)
{
$this->givenName = $gn;
}
public function getGivenName()
{
return $this->givenName;
}
public function setFamilyName($fn)
{
$this->familyName = $fn;
}
public function getFamilyName()
{
return $this->familyName;
}
public function setSuffix($suffix)
{
$this->suffix = $suffix;
}
public function getSuffix()
{
return $suffix;
}
}
$person = new Person();
$person->setPrefix("Mr.");
$person->setGivenName("John");
echo($person->getPrefix());
echo($person->getGivenName());
?>
I there a way in PHP (5.4 preferably), to combine these return values into one function, this way it models a little bit more like the revealing module pattern in JavaScript?
UPDATE:
OK, I am now beginning to learn that within PHP, it is normative to return a single value from a function, but you "can" return an array of multiple values. This is the ultimate answer to my question and what I will dive into some practices with this understanding.
small example -
function fruit () {
return [
'a' => 'apple',
'b' => 'banana'
];
}
echo fruit()['b'];
Also an article I ran across on stackoverflow on the topic...
PHP: Is it possible to return multiple values from a function?
Good luck!
You sound like you want the __get() magic method.
class Thing {
private $property;
public function __get($name) {
if( isset( $this->$name ) {
return $this->$name;
} else {
throw new Exception('Cannot __get() class property: ' . $name);
}
}
} // -- end class Thing --
$athing = new Thing();
$prop = $athing->property;
In the case that you want all of the values returned at once, as in Marc B's example, I'd simplify the class design for it thusly:
class Thing {
private $properties = array();
public function getAll() {
return $properties;
}
public function __get($name) {
if( isset( $this->properties[$name] ) {
return $this->properties[$name];
} else {
throw new Exception('Cannot __get() class property: ' . $name);
}
}
} // -- end class Thing --
$athing = new Thing();
$prop = $athing->property;
$props = $athing-> getAll();
Perhaps
public function getAll() {
return(array('prefix' => $this->prefix, 'givenName' => $this->giveName, etc...));
}
In effect, if I have a class c and instances of $c1 and $c2
which might have different private variable amounts but all their public methods return the same values I would like to be able to check that $c1 == $c2?
Does anyone know an easy way to do this?
You can also implement a equal($other) function like
<?php
class Foo {
public function equals($o) {
return ($o instanceof 'Foo') && $o.firstName()==$this.firstName();
}
}
or use foreach to iterate over the public properties (this behaviour might be overwritten) of one object and compare them to the other object's properties.
<?php
function equalsInSomeWay($a, $b) {
if ( !($b instanceof $a) ) {
return false;
}
foreach($a as $name=>$value) {
if ( !isset($b->$name) || $b->$name!=$value ) {
return false;
}
}
return true;
}
(untested)
or (more or less) the same using the Reflection classes, see http://php.net/manual/en/language.oop5.reflection.php#language.oop5.reflection.reflectionobject
With reflection you might also implement a more duck-typing kind of comparision, if you want to, like "I don't care if it's an instance of or the same class as long as it has the same public methods and they return the 'same' values"
it really depends on how you define "equal".
It's difficult to follow exactly what you're after. Your question seems to imply that these public methods don't require arguments, or that if they did they would be the same arguments.
You could probably get quite far using the inbuilt reflection classes.
Pasted below is a quick test I knocked up to compare the returns of all the public methods of two classes and ensure they were they same. You could easily modify it to ignore non matching public methods (i.e. only check for equality on public methods in class2 which exist in class1). Giving a set of arguments to pass in would be trickier - but could be done with an array of methods names / arguments to call against each class.
Anyway, this may have some bits in it which could be of use to you.
$class1 = new Class1();
$class2 = new Class2();
$class3 = new Class3();
$class4 = new Class4();
$class5 = new Class5();
echo ClassChecker::samePublicMethods($class1,$class2); //should be true
echo ClassChecker::samePublicMethods($class1,$class3); //should be false - different values
echo ClassChecker::samePublicMethods($class1,$class4); //should be false -- class3 contains extra public methods
echo ClassChecker::samePublicMethods($class1,$class5); //should be true -- class5 contains extra private methods
class ClassChecker {
public static function samePublicMethods($class1, $class2) {
$class1methods = array();
$r = new ReflectionClass($class1);
$methods = $r->getMethods();
foreach($methods as $m) {
if ($m->isPublic()) {
#$result = call_user_method($m->getName(), $class1);
$class1methods[$m->getName()] = $result;
}
}
$r = new ReflectionClass($class2);
$methods = $r->getMethods();
foreach($methods as $m) {
//only comparing public methods
if ($m->isPublic()) {
//public method doesn't match method in class1 so return false
if(!isset($class1methods[$m->getName()])) {
return false;
}
//public method of same name doesn't return same value so return false
#$result = call_user_method($m->getName(), $class2);
if ($class1methods[$m->getName()] !== $result) {
return false;
}
}
}
return true;
}
}
class Class1 {
private $b = 'bbb';
public function one() {
return 999;
}
public function two() {
return "bendy";
}
}
class Class2 {
private $a = 'aaa';
public function one() {
return 999;
}
public function two() {
return "bendy";
}
}
class Class3 {
private $c = 'ccc';
public function one() {
return 222;
}
public function two() {
return "bendy";
}
}
class Class4 {
public function one() {
return 999;
}
public function two() {
return "bendy";
}
public function three() {
return true;
}
}
class Class5 {
public function one() {
return 999;
}
public function two() {
return "bendy";
}
private function three() {
return true;
}
}
You can define PHP's __toString magic method inside your class.
For example
class cat {
private $name;
public function __contruct($catname) {
$this->name = $catname;
}
public function __toString() {
return "My name is " . $this->name . "\n";
}
}
$max = new cat('max');
$toby = new cat('toby');
print $max; // echoes 'My name is max'
print $toby; // echoes 'My name is toby'
if($max == $toby) {
echo 'Woohoo!\n';
} else {
echo 'Doh!\n';
}
Then you can use the equality operator to check if both instances are equal or not.
HTH,
Rushi
George: You may have already seen this but it may help: http://usphp.com/manual/en/language.oop5.object-comparison.php
When using the comparison operator (==), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values, and are instances of the same class.
They don't get implicitly converted to strings.
If you want todo comparison, you will end up modifying your classes. You can also write some method of your own todo comparison using getters & setters
You can try writing a class of your own to plugin and write methods that do comparison based on what you define. For example:
class Validate {
public function validateName($c1, $c2) {
if($c1->FirstName == "foo" && $c2->LastName == "foo") {
return true;
} else if (// someother condition) {
return // someval;
} else {
return false;
}
}
public function validatePhoneNumber($c1, $c2) {
// some code
}
}
This will probably be the only way where you wont have to modify the pre-existing class code