I was reading a WordPress tutorial in which the author used something like this (I simplified it):
class WPObject {
public $ID;
public $title;
public $content;
public $status;
public function __construct($wp_post) {
$modifiers = [
'key' => function($k, $v) {
return (substr($k, 0, 5) === "post_") ? substr($k, 5) : $k;
}
];
}
}
The function is supposed to remove the post_ prefix from the wp queried object. The question I have is regarding the function I posted above. That anonymous function seems to return an object with with the properties. When I did a print_r on it I get...
Array
(
[key] => Closure Object
(
[this] => WPObject Object
(
[ID] =>
[title] =>
[content] =>
[status] =>
)
[parameter] => Array
(
[$k] =>
[$v] =>
)
)
)
I'm still learning about anonymous functions and was wondering how/why it does this? If you call an anonymous function from an object, does it create an instance of that object or something?
Also, sorry if I'm using incorrect terminology. Don't have anonymous functions, closures, lambda functions straightened out yet.
Not a new instance, it has a reference to the same object in which it is created since PHP 5.4 I believe. So the closure itself can call properties or methods on that class as if being in that class.
class foo {
public $bar = 'something';
function getClosure(){
return function(){
var_dump($this->bar);
};
}
}
$object = new foo();
$closure = $object->getClosure();
//let's inspect the object
var_dump($object);
//class foo#1 (1) {
// public $bar =>
// string(9) "something"
//}
//let's see what ->bar is
$closure();
//string(9) "something"
//let's change it to something else
$object->bar = 'somethingElse';
//closure clearly has the same object:
$closure();
//string(13) "somethingElse"
unset($object);
//no such object/variables anymore
var_dump($object);
//NULL (with a notice)
//but closure stills knows it as it has a reference
$closure();
//string(13) "somethingElse"
Related
Given that I'm getting different object results depending of the API I query, here are two examples out of 35 I have to implement:
stdClass Object
(
[mid] => 7127.75
[bid] => 7126.6
[ask] => 7128.9
[last_price] => 7128.8
[low] => 7000.0
[high] => 7492.1
[volume] => 53255.4195502
[timestamp] => 1510265647.9803913
)
stdClass Object
(
[Success] => 1
[Message] =>
[Data] => stdClass Object
(
[AskPrice] => 7095
[BidPrice] => 7070
[Low] => 7001
[High] => 7540
[Volume] => 17.38943459
[LastPrice] => 7090
[Change] => -1.02
[Open] => 7163
[Close] => 7090
)
[Error] =>
)
I want to build mapping variable array to access the object easily.
$xmap["a"]["bid"] = "bid";
$xmap["b"]["bid"] = "Data->BidPrice";
Let's assume $content has the first example object, this will work:
print $content->{$xmap["a"]["bid"]}; // the result is 7128.9
As for the second example object, it does not:
print $content->{$xmap["b"]["bid"]}; // the result is PHP Notice: Undefined property: stdClass::$Data->BidPrice in ...
Can this be done or am I stuck with if statements!
First, convert all the objects into assoc. arrays by using json_encode/decode. You'll find this code multiple times here in stackoverflow
$arr = json_decode(json_encode($obj), true);
Second, I recommend a dot-notation for the key-path, plus a tiny function to find the value in a multidimensional array.
Example:
function fromArray($key, $arr) {
$keys = explode('.', $key);
foreach($keys as $k) {
if (!isset($arr[$k]))
return array(); // return empty array
$arr = $arr[$k];
}
return $arr; // can be a scalar value or array
}
$key = 'my.super.array.content';
$array = ['my' => [
'super' => [
'array' =>[
'content'=>4711
]
]
]
];
var_dump($array, fromArray($key, $array));
/*
array(1) {
["my"]=>
array(1) {
["super"]=>
array(1) {
["array"]=>
array(1) {
["content"]=>
int(4711)
}
}
}
}
int(4711)
*/
I found the dot-notation very useful when dealing with complex structures.
You can convert your objects to arrays and build a large mapping array that needs to be maintained and then explode it and loop through it to access the other arrays; or you can try using patterns. I'm thinking Adapter, but maybe another is a better fit. This is using your second object as an example, but just add as many as needed:
class ContentAdapter {
public function __get($name) {
return $this->obj->{$xmap[$name]};
}
}
class ContentAdapter_API_B extends ContentAdapter {
public $xmap = ['bid' => 'BidPrice', 'ask' => 'AskPrice'];
public function __construct($obj) {
$this->obj = $obj->data;
}
}
Now it is consistant regardless of the object since each has an adapter:
$content = new ContentAdapter_API_B($content);
echo $content->bid;
Using your first object you can either create a child as well (ContentAdapter_API_A in case the structure ever changes) or instantiate directly:
$content = new ContentAdapter($content);
echo $content->bid;
Or obviously just use it as is:
echo $content->bid;
An alternate way without inheritance is to use getters:
class ContentAdapter_API_B {
public function __construct($obj) {
$this->obj = $obj->data;
}
public function getBid() { return $this->obj->BidPrice; }
}
So long as the methods are consistent then it will always work:
$content = new ContentAdapter_API_B($content);
echo $content->getBid;
The following is a sample array:
array(11, -2, 4, 35, 0, 8, -9)
I would like to use oop to sort it and generate this result:
Output :
Array ( [0] => -9 [1] => -2 [2] => 0 [3] => 4 [4] => 8 [5] => 11 [6] => 35 )
I was provided the solution far below, which works. What I don't understand is what the __construct is doing. I have a beginner's understanding of how constructors work, but what specifically is the purpose of this constructor?:
public function __construct(array $asort)
{
$this->_asort = $asort;
Is it turning the input into an array?
<?php
class array_sort
{
protected $_asort;
public function __construct(array $asort)
{
$this->_asort = $asort;
}
public function alhsort()
{
$sorted = $this->_asort;
sort($sorted);
return $sorted;
}
}
$sortarray = new array_sort(array(11, -2, 4, 35, 0, 8, -9));
print_r($sortarray->alhsort());
?>
It's a reference to the current object, it's most commonly used in object oriented code.
Here is a reference and a longer primer.
The array $asort is assigned to the variable $_asort of the class and take $_asort as a property of the object created.
The __construct() is initialising the protected $_asort;. Essentially moving your array parameter into a class variable, which is then utilised by alhsort().
For clarification, the Input as you said is already an array once you declare array(...) the construct simple copies it into a variable accessible by the entire array_sort class.
This is way too over engineered!
Why do you want to do this oop when you can simply call
$sortarray = sort(array(11, -2, 4, 35, 0, 8, -9));
To answer your question, __construct() is called whenever the object is instantiated new array_sort(array(11, -2)); instantiates the array_sort object.
Your particular constructor is setting the protected property $_asort with the value passed into the first argument $asort.
<?php
class array_sort
{
public $temp;
public function alhsort(array $sorted)
{
for($i=0; $i<count($sorted)-1; $i++){
for($j=$i+1; $j<count($sorted); $j++){
if($sorted[$i] > $sorted[$j]){
$temp = $sorted[$i];
$sorted[$i] = $sorted[$j];
$sorted[$j] = $temp;
}
}
}
return $sorted;
}
}
$sortarray = new array_sort();
print_r($sortarray->alhsort(array(11, -2, 4, 35, 0, 8, -9)));
?>
I've been wondering how I could check all my parameters efficiently in any function in a clean and concise way.
I've come up with :
function fooBar($myArg, $mySecondArg, $myOptionnalArg = "defaultValue"){
if(!isset($myArg, $mySecondArg, $myOptionnalArg){
die(__FUNCTION__ . ":missing parameter");
}
if(empty($myArg, $mySecondArg, $myOptionnalArg){
die(__FUNCTION__ . ":empty parameter");
}
//Do stuff
}
What I'm looking for is more like:
function fooBar($myArg, $mySecondArg, $myOptionnalArg = "defaultValue"){
$argArray = func_get_args();
foreach($argArray as $a){
if(empty($a)){
die(__FUNCTION__.":".get_arg_name($a)."is empty");
}
if(!isset($a)){
die(__FUNCTION__.":".get_arg_name($a)."is unset");
}
}
//Do stuff
}
Wich doesn't work since get_arg_name(); is pure fiction, and func_get_args(); returns the actual parameters, rather than the ones defined in the prototype.
Could someone give me a hint about it? Any other good/clean way to achieve that is also welcome.
Thanks
With reflection only. Some example:
function test($a, $b, $c) {
$function = new ReflectionFunction(__FUNCTION__);
$parameters = $function->getParameters();
print_r($parameters);
}
test(0, 1, 2);
You will see something like this:
Array
(
[0] => ReflectionParameter Object
(
[name] => a
)
[1] => ReflectionParameter Object
(
[name] => b
)
[2] => ReflectionParameter Object
(
[name] => c
)
)
Its possible to get what you need with using php reflection:
http://php.net/manual/en/book.reflection.php
Please, read more about how to use it.
I would like to have a simple a method, that can give back PHP Activerecord results as simple/associative arrays, not an array of ActiveRecord Objects.
In Ruby I believe this is done perhaps with .map() method. (I am not a Ruby guy...)
What I want is a simple method call, like toArray() in Zend_DB_Table, not a foreach, or something like that, but I can't seem to find it in their docs.
In PHP ActiveRecord getting a result is really easy:
$settings = SystemSettings::all();
But it gives back something like this:
[0] => SystemSettings Object
(
[errors] =>
[attributes:ActiveRecord\Model:private] => Array
(
[param] => author
[value] => Hawle
)
[__dirty:ActiveRecord\Model:private] => Array
(
)
[__readonly:ActiveRecord\Model:private] =>
[__relationships:ActiveRecord\Model:private] => Array
(
)
[__new_record:ActiveRecord\Model:private] =>
)
[1] => SystemSettings Object
(
[errors] =>
[attributes:ActiveRecord\Model:private] => Array
(
[param] => base_url
[value] => example.com
)
[__dirty:ActiveRecord\Model:private] => Array
(
)
[__readonly:ActiveRecord\Model:private] =>
[__relationships:ActiveRecord\Model:private] => Array
(
)
[__new_record:ActiveRecord\Model:private] =>
)
While this is really great in many cases, here, I would just like to have a simple array, like this:
Array
(
[author] => Hawle
[base_url] => example.com
)
I had a similar issue hopefully this can help someone else who stumbles on it. Obviously, this is specific to phpactiverecord.org.
In /lib/Model.php I added the following function:
public function to_array(array $options=array())
{
return $this->serialize('array', $options);
}
In /lib/Serialization.php I added the following class
class arraySerializer extends Serialization
{
public static $include_root = false;
public function to_s()
{
return self::$include_root ? array(strtolower(get_class($this->model)) => $this->to_a()) : $this->to_a();
}
}
I can then call ->to_array() and get an array back.
Hope this helps!
I was searching for the answer to this question in order to produce an array of results that could be easily json-encoded and sent as the response to an ajax call. I wanted only the attributes of each object in the array of results.
Unfortunately, you can't just call to_json() on each result and then json-encode the entire thing; you end up with double-encoding. Fortunately, though, the function and class posted by #willwashburn to solve this problem have now been included in php-activerecord, though they don't seem to have made it into the online documentation.
To return an array of results, do the following:
$data = MyModel::find('all');
foreach ($data as &$result) {
$result = $result->to_array();
}
Your entire result set will now be an array of arrays, containing only the attributes of each object. You can then do something like
echo(json_encode($data));
if you want to send it as the response to an ajax call.
This is my solution:
$posts = Post::find('all');
$arrayResult = array_map(function($res){
return $res->attributes();
}, $posts);
printf('<pre>%s</pre>', print_r($arrayResult, true));
class MyPHPActiveRecord extends PHPActiveRecord {
public function toJSON() {
return json_encode(get_object_vars($this));
}
}
You could do it like this:
funciton ar2array($settings){
$arr = array();
foreach($settings as $fieldObj){
$fieldName = $fieldObj->attributes["param"];
$fieldValue = $fieldObj->attributes["value"];
$arr[$fieldName] = $fieldValue;
}
return $arr;
}
$resultAsYouWant = ar2array($settings);
Hope this helps. Cheers
PS: If ->attributes is private use its accesor method (there must be one) as ->getAttributes() or equivalent.
I found this looking for solution of the same problem that I encountered using Yii framework - there is simplier way to do this in Yii.
$posts = Posts::model()->findAll();
foreach($posts as $result)
{
print_r($result->attributes);
}
It prints simple array as requested:
Array
(
[id] => 1
[title] => Title
[text] => Text
)
Hope it helps somebody.
My solution:
Added the following method to the utils class found in lib\Utils.php
public static function results_to_json($data)
{
$arr = array();
if(count($data)>0){
foreach($data as $row){
array_push($arr, $row->to_array());
}
}
return json_encode($arr);
}
Call by:
echo \ActiveRecord\Utils::results_to_json($dataobject);
Obviously this is no longer relevant to the OP; however, considering that it still took me over an hour to find a solution for this (no thanks to php-activerecords docs), this may help someone else.
$r = Model::find('$id')->attributes();
$a = [];
foreach ($r as $k => $v)
{
$a[$k] = $v;
}
Perhaps not the most elegant, but works perfectly.
I've this sample code:
class A
{
public function A_A() { /* ... */ }
public function A_B() { /* ... */ }
}
class B extends A
{
public function B_A() { /* ... */ }
public function B_B() { /* ... */ }
public function B_C()
{
return get_class_methods($this);
}
}
$a = new A();
$b = new B();
Doing this:
echo '<pre>';
print_r($b->B_C());
echo '</pre>';
Yields the following output:
Array
(
[0] => B_A
[1] => B_B
[2] => B_C
[3] => A_A
[4] => A_B
)
How can I make it return only the following methods?
Array
(
[0] => B_A
[1] => B_B
[2] => B_C
)
I've a method in class A that should call all the methods in class B, the problem is of course that it leads to a infinite loop due to the values returned by get_class_methods().
You might need full strength Reflection. However, before you go there, it might be worth trying something like this.
array_diff(get_class_methods($this), get_class_methods(get_parent_class($this)))
You can't. Part of the functionality of extending a class is that you get all of the methods of the class you extended, in the new class, identical to as if you defined them in the new class itself.