I have a own Array class. Like this:
myArray::fetch('site.meta.keywords'); // return Array(...)
At the same time, How can I do like this?
myArray::fetch('site.meta.keywords'); // return Array(...)
myArray::fetch('site.meta.keywords')->as_object(); // return Object{...}
Is it possible in PHP?
You can't because an array doesn't have an as_object method. I would make a separate fetchAsObject method in your array class, or introduce an optional asObject parameter (boolean, default false) to your existing fetch method.
You should take a look at ArrayObject, it behaves the same as any other array and you can extend it (or your class?).
In your case I'd return something like MyArrayObject (your class extending ArrayObject with method as_object() etc.).
If in first case you are returning raw PHP Array it is not possible.
You can do that way:
public static function fetch($key, $as_object = false)
{
//in $data you have your array
return ($as_object) ? (object)$data : $data;
}
myArray::fetch('site.meta.keywords'); //return array
myArray::fetch('site.meta.keywords', true); //return object
Or just simply like that:
$dataAsArray = myArray::fetch('site.meta.keywords');
$dataAsObject = (object)myArray::fetch('site.meta.keywords');
Related
I'm trying to filter an array of objects implementing a specific interface (which simply defines the isComplete(): bool method) based on the result of that method. array_filter doesn't work because it can't call a method on each object to determine whether to filter it (or can it?). I've tried writing a function that takes the splatted array as an argument by reference, this doesn't work either:
function skipIncomplete(CompletableObjectInterface &...$objects): array {
$skipped = [];
foreach ($objects as $index => $item) {
if (!$item->isComplete()) {
$skipped[] = $item->id ?? $index;
unset($objects[$index]);
}
}
return $skipped;
}
The original elements passed in simply don't end up getting unset.
I'm looking for a way that doesn't include creating an entirely new Collection class to hold my CompletableObjects for complexity reasons. I really want to keep the type hint so no one can pass in a generic array, causing runtime errors when the function tries to call $item->isComplete.
Is there any way I can achieve this in PHP 7.3.15?
Added a filter, please comment as to what is wrong with this type of approach:
<?php
interface CompletableObjectInterface {
public function isComplete() : bool;
}
class Foo implements CompletableObjectInterface
{
public function isComplete() : bool
{
return false;
}
}
class Bar implements CompletableObjectInterface
{
public function isComplete() : bool
{
return true;
}
}
$foo = new Foo;
$bar = new Bar;
$incomplete = array_filter([$foo, $bar], function($obj) { return !$obj->isComplete();});
var_dump($incomplete);
Output:
array(1) {
[0]=>
object(Foo)#1 (0) {
}
}
Looks like you got a bit hung up on a wrong understanding of the ... syntax for a variable number of arguments.
You are passing in one array, and the $objects parameter will therefore contain that array in the first index, i.e. in $objects[0].
So in theory you could just change your line
unset($objects[$index]);
to
unset($objects[0][$index]);
However, I do not really see why the variable number of arguments syntax is used at all, since you apparently are just expecting one array of values (objects in this case) as an argument to the function. Therefore I'd recommend you just remove the ... from the argument list and your solution does what you wanted.
Alternatively you can of course add an outer foreach-loop and iterate over all passed "arrays of objects", if that is an use case for you.
If I use this method to retrieve data I cannot parse it in my PHP like this $data[0]['string']. PHP just says this is an Object and it cannot parse it as Array
error message
Cannot use object of type App\Entity\MyEntity as array
Controller code:
$data = $this->em
->getRepository(Myclass::class)
->findBy(['foo' => $var]);
How can I return a parsable array from a simple findBy() directly from the controller without having to go through the Repository and QueryBuilder with ->getArrayResult() ?
All you need to do is to create your custom function in your repository:
public function findItByFoo($var){
$qb = $this->createQueryBuilder('myClass');
$qb->select("myClass")
->where('foo = :var')
->setParameter('var', $var);
$result = $qb->getQuery()->getArrayResult();
return $result;
}
You cannot achieve this with built-in findBy method. More specifically, the findBy definition is:
$repository->findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null);
As you can see for yourself there is not any argument for the hydration mode.
Finally, since you want to hydrate your entities as arrays instead of objects, and you want to do that in your controller, the only solution is something like this:
$data = $this->em->getRepository(Myclass::class)->createQueryBuilder('m')
->select("m")->where('foo = :var')->setParameter('var', $var)
->getQuery()->getArrayResult();
As you can see, it almost identical with the code in the findItByFoo() function I wrote above, I just wanted to mark that you can do that also in your controller (even not suggested, programmatically speaking).
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 an array whose items are of a certain object type, let it be my_object.
The class defining the my_objects has a function that I want to use to filter the array. How can I specify that function when calling array_filter?
class my_class{
private $exclude;
public filter_function(){
return !$this->exclude;
}
}
$array=array($my_object1, $my_object2, ....);
$filtered=array_filter($array,'filter_function');//obviously does not work
my_object1 , my_object2 , ... are all instances of my_class and I want that the
$my_object1->filter_function()
$my_object2->filter_function()
,.....
be called for filtering the array.
If you want to filter the array based on return value of each individual object's filter_function method call, you could simply:
array_filter($array, function($obj) { return $obj->filter_function(); });
No need to clutter the original class with static methods as in Mark's answer.
You need to indicate the object as well as the method in your callback, using an array syntax as shown in the php docs for callbacks
class my_class{
private $exclude;
public filter_function(){
return !$this->exclude;
}
}
$array = array($my_object1, $my_object2, ....);
$classFilter = new my_class();
$filtered = array_filter($array,[$classFilter, 'filter_function']);
In this case, you need to create an instance first, then use that instantiated object as the first element in the callback, and the method name as the second element
EDIT
However, if you're trying to filter this collection of my_class objects based on whether individual objects have the exclude set, then you need to have a filter method for the collection:
class my_class{
private $exclude;
public filter_function(){
return !$this->exclude;
}
public static filter_collection($value){
return $value->filter_function();
}
}
$array = array($my_object1, $my_object2, ....);
$filtered = array_filter($array,['my_class', 'filter_collection']);
I would like to be able to access the value of a property from a single string...
$obj->Test->FGH = "Well Done!";
I have tried
var_dump($obj->{'Test->FGH'});
And
var_dump( eval( '$obj->Test->FGH' ) );
I know, the following will work, but it has to be defined from a string
var_dump ($obj->Test->FGH);
I also know the following will work, but it doesnt access the FGH property;
var_dump ($obj->{'Test'});
So how is it possible to return the value of $obj->Test->FGH, from a string?
You need to iterate through the object structure recursively until you find the property.
Here is a recursive function that does the job.
It only works if the searched value is not an object. You will have to modify it if the property you are looking for is an object, relying on wether the $props array is empty or not.
The $props argument needs to be ordered in the same way the object properties are nested.
You could also modify it to have a string as second argument, for example Test/FGH
function search_property($obj, $props) {
$prop = array_shift($props);
// If this is an object, go one level down
if (is_object($obj->$prop)) {
return search_prop($obj->$prop, $props);
}
if (!isset($obj->$prop)) {
return false;
}
return $obj->$prop;
}
$val = search_property($obj, array('Test', 'FGH'));