setters/getters in one method - php

Just an idea:
example (in PHP):
to set name:
$object->name('name');
to get name:
$object->name();
If no argument: the method is used as getter, else as setter. For simple getters/setter. Stupid, whatever, maybe?
edit: to follow up on the answers: I don't really like get and set because I prefer to have the interface as explicit as possible. When there are only a few properties it's also overkill IMHO. So I'd like to narrow it down to classes/objects with a couple of explicit getters/setters.

The problem is it would be hard to follow. I'd much rather use PHP5's __get and __set so it is more natural to get and set variables, and everyone would know exactly what I am doing. IE:
class myClass
{
function __get($name)
{
return $this->array[$name];
}
function __set($name, $value)
{
$this->array[$name] = $value;
}
function print()
{
echo $this->array['test'];
}
}
$obj = new myClass;
$obj->test = "Hi";
echo $obj->test; //echos Hi.
$obj->print(); //echos Hi.

It can be done using the __call() magic method.
class Test {
public function __call($name, array $args) {
$variable =& $this->$name;
if(!empty($args)) {
$variable = $args[0];
}
return $variable;
}
}

Sure, you could do that if it makes sense in your application, otherwise I would just use the standard getters/setters which have already been set up for you. Your function could look something like this:
public function name($val = null)
{
if (is_null($val))
{
return $this->name;
}
else
{
$this->name = $val;
}
}

Related

Override recursion limits for __get and __set on the same property

Is there a way to Override recursion limits for __get and __set on the same property. I want to be able to handle the second reentry differently than the first entry.
This code example isn't practical but the simplest to make the point.
class Foo {
public function __set($name,$value){
print "$name entered\n";
this->$name = $value; // want it to recurse here
}
}
$a = new Foo();
$a->baz = "derp";
print $a->baz;
// should get (cannot test at the moment)
// baz entered
// derp <- you get derp because the current php implementation creates an instance variable from the second call to __set
My Internet is down so I'm typing on my phone so typos are likely.
There's no way to do this with that syntax. Just call __set directly instead, e.g.:
class Foo {
public function __set($name, $value) {
print "$name entered\n";
$this->__set($name, $value);
}
}
I know this is a old question, but I think this is what you actually were looking for.
<?php
class Foo {
private $_data = array();
public function __set($name,$value){
print "$name entered\n";
$this->_data[$name] = $value;
}
public function __get($name){
if(array_key_exists($name, $this->_data)){
return $this->_data[$name];
} else {
return false;
}
}
}
$a = new Foo();
$a->baz = "derp";
print $a->baz;
?>
http://phpfiddle.org/main/code/4h0-an7

can I pass __construct parameters after a class has been instantiated into an object?

I have a similar code snippet like this
class Search
{
public function search($for, $regEx, $flag) //I would like this to be the constructor
{
// logic here
return $this;
}
}
Then I have another class that creates an object from it, later than tries to use the object.
class MyClass
{
public function start()
{
$this->search = new Search();
}
public function load()
{
$this->search($for, $regEx, $flag);
}
}
My question is, is it possible to create an object first THEN give it the parameters?
I know there are some way around this BUT I only ask because I want to use the object like this
$this->search($params);
// I have my methods chained, so I could use it in one line like
// $this->search($params)->hasResults();
if ($this->search->hasResults()) {
echo 'found stuff';
} else {
echo 'didn't find anything';
}
The way I have it set up right now, I would need to use it like this
$this->search->search($params);
if ($this->search->hasResults()) {
echo 'found stuff';
} else {
echo 'didn't find anything';
}
I have a method called search() that does the logic, and I don't want to be redundant in my naming nor do I want to change the name of the method.
I know another way to keep the visual appeal sane I could pass a variable like so
$search = $this->search->search($params);
then
$search->hasResults();
At the same time I am trying to introduce myself to new OOP concepts and learn from them. Would this require passing things by reference? or setting up some type of magic method?
While the previous anwsers show that you can, I wouldn't use it, because it breaks the concept of encapsulation. A proper way to achieve what you want is the following
class Search
{
public function __constructor($for='', $regEx='', $flag='')
{
$this->Setup($for, $regEx, $flag);
}
public function Setup($for, $regEx, $flag)
{
//assign params
//clear last result search
//chain
return $this;
}
public function search()
{
// logic here
return $this;
}
}
In this way, you can reuse the object and have the params in the constructor, without breaking encapsulation.
Yes it is possible
See the below example
<?php
class a{
public $a = 5;
public function __construct($var){
$this->a = $var;
}
}
$delta = new a(10);
echo $delta->a."\n";
$delta->__construct(15);
echo $delta->a."\n";
Output will be:
10 15
Yep, you can.
class Example {
public $any;
function __counstruct($parameters,$some_text) {
$this->any=$some_text;
return $this->any;
}
}
You can call constructor:
$obj = new Example (true,'hello');
echo $obj->any;
$obj->__construct(true,'bye-bye');
echo $obj->any;
I was able to create the visual coding I wanted by using the __call() magic method like this
public function __call($name, $params)
{
$call = ucfirst($name);
$this->$name = new $call($params);
}
from there I could use this
$this->test->search($params);
$this->test->search->hasResults();
I of course now set the search() method to the class constructor

Is it possible to use mixins in php

I came to know about mixins.So my doubt is, is it possible to use mixins in php?If yes then how?
Use Trait introduced in PHP 5.4
<?php
class Base {
public function sayHello() {
echo 'Hello ';
}
}
trait SayWorld {
public function sayHello() {
parent::sayHello();
echo 'World!';
}
}
class MyHelloWorld extends Base {
use SayWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
?>
which prints Hello World!
http://php.net/manual/en/language.oop5.traits.php
This answer is obsolete as of PHP 5.4. See Jeanno's answer for how to use traits.
It really depends on what level of mixins you want from PHP. PHP handles single-inheritance, and abstract classes, which can get you most of the way.
Of course the best part of mixins is that they're interchangeable snippets added to whatever class needs them.
To get around the multiple inheritance issue, you could use include to pull in snippets of code. You'll likely have to dump in some boilerplate code to get it to work properly in some cases, but it would certainly help towards keeping your programs DRY.
Example:
class Foo
{
public function bar( $baz )
{
include('mixins/bar');
return $result;
}
}
class Fizz
{
public function bar( $baz )
{
include('mixins/bar');
return $result;
}
}
It's not as direct as being able to define a class as class Foo mixin Bar, but it should get you most of the way there. There are some drawbacks: you need to keep the same parameter names and return variable names, you'll need to pass other data that relies on context such as func_get_args_array or __FILE__.
Mixins for PHP (PHP does not implement Mixins natively, but this library will help)
First google result for "php5 mixin": http://www.sitepoint.com/forums/php-application-design-147/ruby-like-mixins-php5-332491.html
First google result for "php mixin": http://www.advogato.org/article/470.html
Short answer: yes, but not natively (yet, evidently, as #mchl notes). Check those out.
Longer answer: if you're using runkit, checkout runkit_method_copy(): "Copies a method from class to another."
I based mixins functionality on the blog entry found at jansch.nl.
class Node
{
protected $__decorator_lookup = array();
public function __construct($classes = array())
{
foreach($classes as $class)
if (class_exists($class))
{
$decorator = new $class($this);
$methods = get_class_methods($decorator);
if (is_array($methods))
foreach($methods as $method)
$this->__decorator_lookup[strtolower($method)] = $decorator;
}
else
trigger_error("Tried to inherit non-existant class", E_USER_ERROR);
}
public function __get($name)
{
switch($name)
{
default:
if ($this->__decorator_lookup[strtolower($name)])
return $this->__call($name);
}
}
public function __call($method, $args = array())
{
if(isset($this->__decorator_lookup[strtolower($method)]))
return call_user_func_array(array($this->__decorator_lookup[strtolower($method)], $method), $args);
else
trigger_error("Call to undefined method " . get_class($this) . "::$method()", E_USER_ERROR);
}
public function __clone()
{
$temp = $this->decorators;
$this->decorators = array();
foreach($temp as $decorator)
{
$new = clone($decorator);
$new->__self = $this;
$this->decorators[] = $new;
}
}
}
class Decorator
{
public $__self;
public function __construct($__self)
{
$this->__self = $__self;
}
public function &__get($key)
{
return $this->__self->$key;
}
public function __call($method, $arguments)
{
return call_user_func_array(array($this->__self, $method), $arguments);
}
public function __set($key, $value)
{
$this->__self->$key = $value;
}
}
class Pretty extends Decorator
{
public function A()
{
echo "a";
}
public function B()
{
$this->b = "b";
}
}
$a = new Node(array("Pretty"));
$a->A(); // outputs "a"
$a->B();
echo($a->b); // outputs "b"
EDIT:
As PHP clone is shallow, added __clone support.
Also, bear in mind that unset WON'T work (or at least I've not managed to make it work) within the mixin. So - doing something like unset($this->__self->someValue); won't unset the value on Node. Don't know why, as in theory it should work. Funny enough unset($this->__self->someValue); var_dump(isset($this->__self->someValue)); will produce correctly false, however accessing the value from Node scope (as Node->someValue) will still produce true. There's some strange voodoo there.

Php Magic Methods and Empty

Having the following code
class test {
private $name;
public function __get($name){
return $name;
}
public function __set($name,$value){
$this->name = $value;
}
}
$obj = new test();
$obj->a = 2;
if (!empty($obj->a)) {
echo 'not empty';
}
This is calling __isset. But this is not being defined so it always return empty. What is the best way to check for a non empty property?
Update :changing the class is not a solution because it's a 3th party component and it has to remain intact.
If you can't change the class, I think the only possible workaround is using a temporary variable.
$obj->a = 2;
$test = $obj->a;
if (!empty($test)) {
echo 'not empty';
}
I know I am very late to the party here, however I am posting this for the edificationof any who may stumble across this question.
Firstly, I believe that the test class is wrong and if that is really what the 3rd party component does, I would chuck it out because it's rubbish. Do you really want all property names to map internally to the single property 'name', and thereby overwrite each other? Do you really want all property names to be returned as the property value? The code should look like this:
class test {
public function __get($name){
return $this->$name;
}
public function __set($name,$value){
$this->$name = $value;
}
}
Secondly, you can change the class, even if it has to remain intact. That's the point of inheritance. This is the open-closed principle. If the functions are incorrect, simply extend test like this to correct them:
class test {
private $name;
public function __get($name){
return $name;
}
public function __set($name,$value){
$this->name = $value;
}
}
class my_test extends test
{
public function __get($name)
{
return $this->$name;
}
public function __set($name,$value){
$this->$name = $value;
}
}
You shouldn't need to define __isset() as the corrected code will do what it is meant to do, but if you did you could do that here too.
Now the following will do what it is supposed to do (note the change of class name):
$obj = new my_test();
$obj->a = 2;
if (!empty($obj->a)) {
echo 'not empty';
}
change
public function __set($name,$value){
$this->name = $value;
}
To
public function __set($name,$value){
$this->$name = $value;
}
And then try
It does not make sense when used with anything other than the variable; ie empty (addslashes ($ name)) does not make sense, since it will be checked by anything other than a variable as a variable with a value of FALSE.
In your case, you should use the type conversion:
if ((bool)$obj->a) {
echo 'not empty';
}

PHP get_called_class() alternative

I've got an Abstract PHP superclass, which contains code that needs to know which subclass its running under.
class Foo {
static function _get_class_name() {
return get_called_class();
//works in PHP 5.3.*, but not in PHP 5.2.*
}
static function other_code() {
//needs to know
echo self::_get_class_name();
}
}
class Bar extends Foo {
}
class FooBar extends Foo {
}
Bar::other_code(); // i need 'Bar'
FooBar::other_code(); // i need 'FooBar'
This would work if I called the function get_called_class() -- however, this code is going to be run in PHP version 5.2.*, so that function is not available.
There's some custom PHP implementations of get_called_class() out there, but they all rely on going thru the debug_backtrack(), parsing a file name & line number, and running a regex (as the coder is not aware that PHP 5.2 has reflection) to find the class name. This code needs to be able to be run with php, ie. not only from a .php file. (It needs to work from a php -a shell, or an eval() statement.)
Ideally, a solution would work without requiring any code to be added to the subclasses… The only potential solution I can see though is adding the following code to each subclass, which is obviously a disgusting hack:
class FooBar extends Foo {
static function _get_class_name() {
return 'FooBar';
}
}
EDIT: Wait, this doesn't even seem to work. It would've been my last resort. Can anybody think of something similar to this solution that'd get me the required functionality. Ie., I'm willing to accept a solution that requires me to add one function or variable to each subclass telling it what its class name is. Unfortunately, it seems that calling self::_get_class_name() from the superclass calls the parent class' implementation, even if the subclass has overridden it.
In reality it is often helpful to know the actual called (sub)class when executing a superclass method, and I disagree that there's anything wrong with wanting to solve this problem.
Example, my objects need to know the class name, but what they do with that information is always the same and could be extracted into a superclass method IF I was able to get the called class name. Even the PHP team thought this was useful enough to include in php 5.3.
The correct and un-preachy answer, as far as I can tell, is that prior to 5.3, you have to either do something heinous (e.g. backtrace,) or just include duplicate code in each of the subclasses.
Working solution:
function getCalledClass(){
$arr = array();
$arrTraces = debug_backtrace();
foreach ($arrTraces as $arrTrace){
if(!array_key_exists("class", $arrTrace)) continue;
if(count($arr)==0) $arr[] = $arrTrace['class'];
else if(get_parent_class($arrTrace['class'])==end($arr)) $arr[] = $arrTrace['class'];
}
return end($arr);
}
This is not possible.
The concept of "called class" was introduced in PHP 5.3. This information was not tracked in previous versions.
As an ugly work-around, you could possibly use debug_backtrace to look into the call stack, but it's not equivalent. For instance, in PHP 5.3, using ClassName::method() doesn't forward the static call; you have no way to tell this with debug_backtrace. Also, debug_backtrace is relatively slow.
The PHP/5.2 alternative to late static binding that keeps duplicate code to the minimum while avoiding weird hacks would be to create one-liners on child classes that pass the class name as argument:
abstract class Transaction{
public $id;
public function __construct($id){
$this->id = $id;
}
protected static function getInstanceHelper($class_name, $id){
return new $class_name($id);
}
}
class Payment extends Transaction{
public static function getInstance($id){
return parent::getInstanceHelper(__CLASS__, $id);
}
}
class Refund extends Transaction{
public static function getInstance($id){
return parent::getInstanceHelper(__CLASS__, $id);
}
}
var_dump( Payment::getInstance(1), Refund::getInstance(2) );
object(Payment)#1 (1) {
["id"]=>
int(1)
}
object(Refund)#2 (1) {
["id"]=>
int(2)
}
The solution is:
get_class($this);
However, I don't know if this sentence works in static functions. Give it a try and tell me your feedback.
This hack includes the heinous use of debug_backtrace... not pretty, but it does the job:
<?php
function callerName($functionName=null)
{
$btArray = debug_backtrace();
$btIndex = count($btArray) - 1;
while($btIndex > -1)
{
if(!isset($btArray[$btIndex]['file']))
{
$btIndex--;
if(isset($matches[1]))
{
if(class_exists($matches[1]))
{
return $matches[1];
}
else
{
continue;
}
}
else
{
continue;
}
}
else
{
$lines = file($btArray[$btIndex]['file']);
$callerLine = $lines[$btArray[$btIndex]['line']-1];
if(!isset($functionName))
{
preg_match('/([a-zA-Z\_]+)::/',
$callerLine,
$matches);
}
else
{
preg_match('/([a-zA-Z\_]+)::'.$functionName.'/',
$callerLine,
$matches);
}
$btIndex--;
if(isset($matches[1]))
{
if(class_exists($matches[1]))
{
return $matches[1];
}
else
{
continue;
}
}
else
{
continue;
}
}
}
return $matches[1];
}
I have asked a question like this before, because I wanted a parent to have a factory method that was something like this
public static function factory() {
return new __CLASS__;
}
But it always returned the parent class, not the inherited one.
I was told that it is not possible without late static binding. It was introduced in PHP 5.3. You can read the documentation.
This function does the same job but works with instances too:
if (!function_exists('get_called_class')) {
function get_called_class() {
$bt = debug_backtrace();
/*
echo '<br><br>';
echo '<pre>';
print_r($bt);
echo '</pre>';
*/
if (self::$fl == $bt[1]['file'] . $bt[1]['line']) {
self::$i++;
} else {
self::$i = 0;
self::$fl = $bt[1]['file'] . $bt[1]['line'];
}
if ($bt[1]['type'] == '::') {
$lines = file($bt[1]['file']);
preg_match_all('/([a-zA-Z0-9\_]+)::' . $bt[1]['function'] . '/', $lines[$bt[1]['line'] - 1], $matches);
$result = $matches[1][self::$i];
} else if ($bt[1]['type'] == '->') {
$result = get_class($bt[1]['object']);
}
return $result;
}
}
<?php
class Foo {
private static $instance;
static function _get_class_name() {
return self::myNameIs();
}
static function other_code() {
//needs to know
echo self::_get_class_name();
}
}
class Bar extends Foo {
public static function myNameIs() {
self::$instance = new Bar();
return get_class(self::$instance);
}
}
class FooBar extends Foo {
public static function myNameIs() {
self::$instance = new FooBar();
return get_class(self::$instance);
}
}
Bar::other_code(); // i need 'Bar'
FooBar::other_code(); // i need 'FooBar'

Categories