I've seen two like these:
$this->propertyName;
$this->methodName();
And I know the code should look like this:
class myClass{
public $propertyName;
public function methodName(){
// statements
}
}
Recently I saw a code like this:
$this->CI->form_validation->set_message('investigate', '{field} ' . lang('wrong'));
What is CI (a method?)? What's form_validation? What's set_message? Are these nested methods? How does its code look like?
A method can return an object. You can assign this object to a variable and then call methods on it:
$objB = $objA->getObjectB();
$objB->someMethod();
Or you can skip the assignment and just inline it;
$objA->getObjectB()->someMethod();
As long as your methods return objects, you can just keep stacking them up:
$objA->getObjectB()->getObjectC()->getObjectD()->getObjectE();
The same holds true for object properties. A public property can hold another object:
$objA->objB = new objectB();
$objA->objB->someMethodOnObjectB();
So methods that return an object and public properties that contain an object can be stacked like this. You can mix them too:
$objA->getObjectB()->somePropertyOnObjectB->someMethod();
Also see Fluent Interface. It's common for objects to return instances of themselves for mutator methods. This allows you to turn this:
$obj = new Object();
$obj->setFoo('foo');
$obj->setBar('bar');
$obj->setBaz('baz');
$obj->doSomething();
Into this:
$obj = new Object();
$obj->setFoo('foo')->setBar('bar')->setBaz('baz')->doSomething();
And in PHP 5.6+, you don't even have to assign the object to a variable, you can dereference the new call directly:
(new Object())->setFoo('foo')->setBar('bar')->setBaz('baz')->doSomething();
CI is a object. In this exact context it is a class property, object type. Theoretically you may have also a method/function that return an object. Something like:
$ClassInstance->MethodThatReturnAnObject()->ObjectProperty = 'bla';
or even
$ClassInstance->MethodThatReturnAnObject()->ObjectMethod();
And the chain may continue with more levels.
Related
I've built a singleton class with chaining methods (to be used in a template).
To make chaining work I need to return new static. It allows the next chain to be added. The problem I have is that I don't want to return the static object if there are no more chains.
Example
<?php
class bread {
public static $array;
public static function blueprints() {
static::$array = array('some', 'values');
return new static;
}
public static function fields() {
return static::$array;
}
}
$blueprints = bread::blueprints();
$fields = bread::blueprints()->fields();
print_r($blueprint) // Returns object - FAIL
print_r($fields ) // Returns array - OK
In the example above I want $blueprints to return an array, because there are no more methods chained on it.
How can that be done?
The simple answer is you cannot do what you want.
Method chaining is not a special thing for Php.
For your example
bread::blueprints()->fields();
This is not different than:
$tmp = bread::blueprints();
$tmp->fields();
So because of the Php does not know the context where the result will be used of it cannot change the return type.
Here is another version of this question:
Check if call is method chaining
However, your class can implement ArrayAccess interface.This will allow you to treat the object like an array without casting and you get total control over how the members are used.
You can try this:
$blueprints = (array)bread::blueprints();
I have the following issue:
The current code of an application I'm working on contains a very large number of definitions like this:
$obj = new stdClass();
$obj->a->b = "something";
This results in: PHP Strict Standards: Creating default object from empty value in [somewhere].
The correct form would be:
$obj = new stdClass();
$obj->a = new stdClass();
$obj->a->b = "something";
Now the problem: Replacing this throughout the code would take ages (consider thousands of cases, with conditions, etc.).
So I was thinking of replacing stdClass with a custom object (this would be a simple replace in code), creating a setter for it that verifies if the variable property is an object, and defines it as object if it is before setting the second property.
So we get:
class MockObject() {
public function __set($property, $value) {
// Do stuff here
}
}
$obj = new MockObject();
$object->a->b = "something";
The problem is that when executing $object->a->b = "something"; setter is not called (because you don't actually set the a property, but the b property).
Is there any way around this? Or is other solution possible?
Note: Explicitly calling the __set() method is not a solution since it would be the same as defining properties as stdClass().
You know about the magic setter.
Use a magic getter also.
If it wants to get a var that does not exists: create one (in an array or something like that) that is an instance of that class.
Why don't you initialize your b variable in the constructor of the A class ?
public function __construct()
{
$this->b = new B();
}
_toString() is called when an object is used as string. How can I do something similar for numerical values, something like __toInt(), or __toArray(). Do such methods exist? Is there a work around? Is it a bad idea to use something like that even if there is a workaround for it?
There is no __toArray magic-method (just check the ones that exist here), but then, there shouldn't be, IMO.
Though people have asked for a magic toArray method, it doesn't look like such a method will be implemented any time soon.
Considering what objects are for, and how we use them, a toInt method wouldn't make much sense, and since all objects can be cast to an array, and can be iterated over, I see very little point in using __toArray anyway.
To "convert" on object to an array, you can use either one of the following methods:
$obj = new stdClass;
$obj->foo = 'bar';
var_dump((array) $obj);
//or
var_dump(json_decode(json_encode($obj), true));
This can be done with both custom objects, as stdClass instances alike.
As far as accessing them as an array, I can't see the point. Why write a slow magic method to be able to do something like:
$bar = 'foo';
$obj[$bar];
if you can do:
$obj->{$bar}
or if you can do:
foreach($obj as $property => $value){}
Or, if you need something a tad more specific, just implement any of the Traversable interfaces.
And for those rare cases, where you want an object to produce an array from specific properties in a very particular way, just write a method for that and call that method explicitly.
class ComplexObject
{
private $secret = null;
private $childObject = null;
public $foo = null;
//some methods, then:
public function toArray()
{//custom array representation of object
$data = array();
foreach($this->childObject as $property => $val)
{
if (!is_object($this->childObject->{$property}))
{
$data[$property] = $val;
}
}
$data['foo'] = $this->foo;
return $data;
}
//and even:
public function toJson()
{
return json_encode($this->toArray());
}
}
Ok, you have to call these methods yourself, explicitly, but that's not that hard, really... is it?
How to combine two variables to obtain / create new variable?
public $show_diary = 'my';
private my_diary(){
return 1;
}
public view_diary(){
return ${"this->"}.$this->show_diary.{"_diary()"}; // 1
return $this->.{"$this->show_diary"}._diary() // 2
}
both return nothing.
Your class should be like following:
class Test
{
public $show_diary;
function __construct()
{
$this->show_diary = "my";
}
private function my_diary(){
return 707;
}
public function view_diary(){
echo $this->{$this->show_diary."_diary"}(); // 707
}
}
It almost looks from your question like you are asking about how to turn simple variables into objects and then how to have one object contain another one. I could be way off, but I hope not:
So, first off, what is the differnce between an object and a simple variable? An object is really a collection of (generally) at least one property, which is sort of like a variable within it, and very often functions which do things to the properties of the object. Basically an object is like a complex variable.
In PHP, we need to first declare the strucutre of the object, this is done via a class statement, where we basicaly put the skeleton of what the object will be into place. This is done by the class statement. However, at this point, it hasn't actually been created, it is just like a plan for it when it is created later.
The creation is done via a command like:
$someVariable= new diary();
This executes so create a new variable, and lays it out with the structure, properties and functions defined in the class statement.
From then on, you can access various properties or call functions within it.
class show_diary
{
public $owner;
public function __construct()
{
$this->owner='My';
}
}
class view_diary
{
public $owner;
public $foo;
public function __construct()
{
$this->foo='bar';
$this->owner=new show_diary();
}
}
$diary= new view_diary();
print_r($diary);
The code gives us two classes. One of the classes has an instance of the other class within it.
I have used constructors, which are a special type of function that is executed each time we create a new instance of a class - basically each time we declare a variable of that type, the __construct function is called.
When the $diary= new view_diary(); code is called, it creates an instance of the view_diary class, and in doing so, the first thing it does is assigns it's own foo property to have the value 'bar' in it. Then, it sets it's owner property to be an instance of show_diary which in turn then kicks off the __construct function within the new instance. That in turn assigns the owner property of the child item to have the value 'My'.
If you want to access single properties of the object, you can do so by the following syntax:
echo $diary->foo;
To access a property of an object inside the object, you simply add more arrows:
echo $diary->owner->owner;
Like this?
$diary = $this->show_diary . '_diary';
return $this->$diary();
Is it possible to instantiate a class from a string, without declaring another variable before ?
It's usually done writing
$className = 'myClass'
$instance = new $className();
but it could be handy to have it shorter like for example
$instance = new ${'className'}();
The purpose is to have objects created (under condition) inside a loop without use of extra vars...
Edit : $className is dynamic, it is hard coded above to explain the situation
See factory pattern.
class Foo {
static function factory($class, array $args = null) {
return new $class($args);
}
}
// class factoring; returns a new instance of requested class ($className)
Foo::factory($className);
I added optional arguments array if you want to set some class properties.
// pass some values for class constructor
Foo::factory($className, array('arg1' => 1, 'arg2' => 2, 'args3' => 3));
Furthermore, you can build "fluid" interfaces so you can "chain" methods when you use that pattern:
Foo::factory($className)->method1()->method2(array('param' => 'value'))->etc();
where method1(), method2() must return $this (the object itself) to chain multiple method calls in one line.
You could make a factory function (or class/method) that takes a class name as a parameter, and then call it with the result of your dynamic PHP code that generates the string. You might consider it a bit cleaner but it's not going to save you any memory or speed.
class foo { }
function factory($class) { return new $class(); }
foreach (...) {
$instance = factory(<some code that returns the string 'foo'>);
}
It's one extra variable, does it really make much of a difference? The answer is that unless you use eval (which comes with security issues) it isn't possible to do it any shorter than your first example.