I use a method in my class that returns an array of members:
public function getArrTranslatable()
{
//------------------------- DECLARE ---------------------------//
return array( $this->artDescription, //
$this->artKeywords, //
$this->artMaintenanceMsg, //
$this->artTitle );
}
In another class, i get that array then iterate on it to perform some actions, like instanciate array for each members:
$arrFieldToTranslate = $p_translatable->getArrTranslatable();
//------------------------- DECLARE ---------------------------//
foreach( $arrFieldToTranslate as $artField )
{
// Instanciate translatable array.
if( $artField == null )
{
$artField = array();
}
$artField[ $p_idLang ] = "";
}
The code seems to work fine, because i pass in the array instanciation, but when i get thoses members in my view, later, they're null.
Related
I have object of class $values like:
Array
(
[0] => App\ValueObject\Features Object
(
[feature:App\ValueObject\Features:private] => CONNECT_NETWORKS_ON_SIGN_UP
[value:App\ValueObject\Features:private] => 1
)
[1] => App\ValueObject\Features Object
(
[feature:App\ValueObject\Features:private] => SHOW_BILLING
[value:App\ValueObject\Features:private] => 1
)
[2] => App\ValueObject\Features Object
(
[feature:App\ValueObject\Features:private] => FEATURE_FLAGS
[value:App\ValueObject\Features:private] => 'activity'
)
)
All array keys are returning boolean type value expect one, which returns string value.
My result with the code:
$arrays = array_map(
function($value) { return [strtolower((string) $value->getFeature())]; },
iterator_to_array($values)
);
return array_merge(...$arrays);
returns list of feature names like:
"features": [
"connect_networks_on_sign_up",
"show_billing",
"feature_flags"
]
What I want to edit is that for the last one we write its value NOT feature name ($value->getValue())
I am assuming that using in_array() PHP function would be the best approach here but I can't find a way to use it within my current method.
Tried with foreach() loop but nothing happens, like it's something wrong:
$features = [];
foreach ($values as $value)
{
$setParam = $value->getFeature();
if ($value == 'FEATURE_FLAGS') {
$setParam = $value->getValue();
}
$features[] = strtolower((string) $setParam);
}
return $features;
Can someone help?
Thanks
You should probably operate on the feature code FEATURE_FLAGS, rather than assuming that the last feature in the array always contains the flags. Using your existing code, that could be as simple as:
$arrays = array_map(
function($value)
{
/*
* If the current Features object has the feature code FEATURE_FLAGS,
* return the value itself, otherwise return the feature code in lowercase
*/
return ($value->getFeature() == 'FEATURE_FLAGS') ? [$value->getValue()]:[strtolower((string) $value->getFeature())];
},
iterator_to_array($values)
);
If you want to define an array of feature codes that you need to treat this way, you can define it internally in the callback, but it is probably a better idea to define it externally. You can then pass it into the callback with use
/*
* Define an array of feature codes that we want to return
* values for
*/
$valueCaptureFeatures = ['FEATURE_FLAGS'];
$arrays = array_map(
function($value) use ($valueCaptureFeatures) // <-- Put our $valueCaptureFeatures in the scope of the callback
{
/*
* If the current Features object has a feature code in the $valueCaptureFeatures array,
* return the value itself, otherwise return the feature code in lowercase
*/
return (in_array($value->getFeature(), $valueCaptureFeatures)) ? [$value->getValue()]:[strtolower((string) $value->getFeature())];
},
iterator_to_array($values)
);
Working example:
// Mock the Features class
class Features
{
private $feature;
private $value;
public function __construct($feature, $value)
{
$this->feature = $feature;
$this->value = $value;
}
public function getFeature()
{
return $this->feature;
}
public function setFeature($feature): void
{
$this->feature = $feature;
}
public function getValue()
{
return $this->value;
}
public function setValue($value): void
{
$this->value = $value;
}
}
// Mock an iterator with test Feature instances
$values = new ArrayIterator( [
new Features('CONNECT_NETWORKS_ON_SIGN_UP', 1),
new Features('SHOW_BILLING', 1),
new Features('FEATURE_FLAGS', 'activity')
]);
/*
* Define an array of feature codes that we want to return
* values for
*/
$valueCaptureFeatures = ['FEATURE_FLAGS'];
$arrays = array_map(
function($value) use ($valueCaptureFeatures) // <-- Put our $valueCaptureFeatures in the scope of the callback
{
/*
* If the current Features object has a feature code in the $valueCaptureFeatures array,
* return the value itself, otherwise return the feature code in lowercase
*/
return (in_array($value->getFeature(), $valueCaptureFeatures)) ? [$value->getValue()]:[strtolower((string) $value->getFeature())];
},
iterator_to_array($values)
);
$output = array_merge(...$arrays);
$expectedResult = [
'connect_networks_on_sign_up',
'show_billing',
'activity'
];
assert($output == $expectedResult, 'Result should match expectations');
print_r($output);
Is it possible to access the properties of a component e.g. blogPosts in the OnStart() function? If so, how?
title = "Blog Category"
url = "/blog/category/:slug/:page?"
[blogPosts]
categoryFilter = ":slug"
postsPerPage = 3
==
function onStart()
{
// Access categoryFilter property
$catfilter = ???
...
}
==
I got to ask why do you need to access the component properties?
You can access the parameter ':slug' $this->param('slug');.
This should work for you to get the array of properties.
function onStart() {
$this['properties'] = collect($this->page->components['blogPosts'])->last()['postsPerPage'];
}
I am adding another way to get the properties from the array. I am assuming that properties is probably always last but if it isn't:
$array = collect($this->page->components['blogPosts'])->toArray();
$properties = [];
foreach ( $array as $key => $property) {
if ( strpos($key, 'properties') !== false ) {
$properties[$key] = $property;
}
}
$this['properties'] = $properties['postsPerPage'];
I have the function/method below inside a class that I'm creating and I'm just wondering what's the best way to handle empty/null arguments.
For example, in the following example, if I wanted to just set just the category when calling the function, I would need to use:
$data = $class->get_top_headlines( null, 'technology' );
Is there any way of calling the function more efficiently? I know I could pass the arguments as an array instead, but just wondered if there's any way of doing something like:
$data = $class->get_top_headlines( $category='technology' ); and automatically leaving the other arguments as their default of null?
public function get_top_headlines( $query=null, $category=null, $country=null, $sources=null, $page_size=null, $page=null ){
$url = $this->api_url . $this->endpoint_top_headlines;
$params = array();
if ( $query !== null ){
$params['q'] = urlencode( $query );
}
if ( $category !== null ){
$params['category'] = $category;
}
if ( $country !== null ){
$params['country'] = $country;
}
if ( $sources !== null ){
$params['sources'] = $sources;
}
if ( $page_size !== null ){
$params['pageSize'] = $page_size;
}
if ( $page !== null ){
$params['page'] = $page;
}
$params['apiKey'] = $this->api_key;
$url_query = http_build_query( $params );
$url = $url . '?' . $url_query;
echo $url;
$obj = $this->get_response( $url );
return $obj;
}
Try passing an array, and then using an array_merge
$data = $class->get_top_headlines(['category' => 'technology']);
Then in your function, have an array of defaults, then do your merge.
$settings = array_merge($settings, $passedInArray);
http://php.net/manual/en/function.array-merge.php
I think
(null, 'technology' );
might be less actual coding but a different solution might be to use OOP. You said it's already a method of a class so you could do something like:
$obj = new thatClass;
$obj->technology = $technology;
$obj->get_top_headlines();
in the Class:
Class thatClass{
$technology = null;
$category = null;
$query = null;
//...
public function get_top_headlines(){
if ( $this->query !== null ){
$params['q'] = urlencode( $this->query );
}
if ( $this->category !== null ){
$params['category'] = $this->category;
}
if ( $this->technology !== null ){
$params['technology'] = $this->technology;
}
//method code..
}
//class code..
}
The problem with this approach is if you need to call that same function again passing a different parameter in the same class instance, depending on your application you might need to manually set back to null the previous parameter (now an object attribute)
I would solve this problem by creating a new class or data structure which will encapsulate all the logic of validating and generating the URL and then use it everywhere I need it.
Here's a sample class.
class HeadLineParameters
{
private $params = [];
public function setQuery($query)
{
// validate/transform query data
$this->params['q'] = urlencode($query);
return $this;
}
public function setCategory($category)
{
// validate/transform category data
$this->params['category'] = $category;
return $this;
}
public function generateUrl()
{
return http_build_query( $this->params );
}
}
$params = new HeadLineParameters;
$params->setQuery($query)
->setCategory($category);
You just pass one argument and you know that it's just an instance of HeadLineParameters.
$class->get_top_headlines($params);
This solution doesn't pollute your current class with unnecessary state or fields. It is easy to test, and it has only one job. You can extend it easily, you can set default values, you can also validate it as you like.
Edit: Why you shouldn't add more fields to your current class?
If you add more fields to your current class you'll be breaking the single responsibility principle, and any method of this class can change these fields too. It shouldn't be a problem if these fields really belong there and more methods require them. This is fine if you are using OOP.
I am not sure what other people think about passing associated arrays to functions, but they are hard to handle if you have no documentation available. I have had trouble with them when reading some external code, and most of time I wasn't sure what's the data I was dealing with.
I see there are about a hundred different questions on here for Creating default object from empty value. None of them really seem to help with my issue.
I am assigning a child object of the same class in a method. This triggers the Creating default object from empty value error.
class myClass {
function __construct($rootName, $allowHTML = false, $endTag = true) {
$this->rootElement = $rootName;
$this->elements = array();
$this->attributes = array();
$this->value = "";
$this->allowHTML = $allowHTML;
$this->endTag = $endTag;
$this->styles = array();
$this->childID = 0;
}
// ... OTHER METHODS HERE (ALL PROPERTIES DECLARED)
function assignElement(&$theElement) {
// Get the index.
$index = count($this->elements);
// Assign the element.
$this->elements[$index] = $theElement;
if (get_class($theElement) == get_class($this)) {
$this->elements[$index]->childID = $index;
}
// Return the node.
return $this->elements[$index];
}
}
The error occurs on $this->elements[$index]->childID = $index;. How do I handle this properly?
Seems like you are passing NULL to the assignElement. get_class called with no arguments or null as argument, returns class of the object where it is defined, so your if conditions is true for null values. You should use is_object first.
I know that it is possible to call a function with a variable number of parameters with call_user_func_array() found here -> http://php.net/manual/en/function.call-user-func-array.php . What I want to do is nearly identical, but instead of a function, I want to call a PHP class with a variable number of parameters in it's constructor.
It would work something like the below, but I won't know the number of parameters, so I won't know how to instantiate the class.
<?php
//The class name will be pulled dynamically from another source
$myClass = '\Some\Dynamically\Generated\Class';
//The parameters will also be pulled from another source, for simplicity I
//have used two parameters. There could be 0, 1, 2, N, ... parameters
$myParameters = array ('dynamicparam1', 'dynamicparam2');
//The instantiated class needs to be called with 0, 1, 2, N, ... parameters
//not just two parameters.
$myClassInstance = new $myClass($myParameters[0], $myParameters[1]);
You can do the following using ReflectionClass
$myClass = '\Some\Dynamically\Generated\a';
$myParameters = array ('dynamicparam1', 'dynamicparam2');
$reflection = new \ReflectionClass($myClass);
$myClassInstance = $reflection->newInstanceArgs($myParameters);
PHP manual: http://www.php.net/manual/en/reflectionclass.newinstanceargs.php
Edit:
In php 5.6 you can achieve this with Argument unpacking.
$myClass = '\Some\Dynamically\Generated\a';
$myParameters = ['dynamicparam1', 'dynamicparam2'];
$myClassInstance = new $myClass(...$myParameters);
I implement this approach a lot when function args are > 2, rather then end up with an Christmas list of arguments which must be in a specific order, I simply pass in an associative array. By passing in an associative array, I can check for necessary and optional args and handle missing values as needed. Something like:
class MyClass
{
protected $requiredArg1;
protected $optionalArg1;
public function __construct(array $options = array())
{
// Check for a necessary arg
if (!isset($options['requiredArg1'])) {
throw new Exception('Missing requiredArg1');
}
// Now I can just localize
$requiredArg1 = $options['requiredArg1'];
$optionalArg1 = (isset($options['optionalArg1'])) ? $options['optionalArg1'] : null;
// Now that you have localized args, do what you want
$this->requiredArg1 = $requiredArg1;
$this->optionalArg1 = $optionalArg1;
}
}
// Example call
$class = 'MyClass';
$array = array('requiredArg1' => 'Foo!', 'optionalArg1' => 'Bar!');
$instance = new $class($array);
var_dump($instance->getRequiredArg1());
var_dump($instance->getOptionalArg1());
I highly recommend using an associative array, however it is possible to use a 0-index array. You will have to be extremely careful when constructing the array and account for indices that have meaning, otherwise you will pass in an array with offset args and wreck havoc with your function.
You can do that using func_get_args().
class my_class {
function __construct( $first = NULL ) {
$params = func_get_args();
if( is_array( $first ) )
$params = $first;
// the $params array will contain the
// arguments passed to the child function
foreach( $params as $p )
echo "Param: $p\n";
}
}
function my_function() {
$instance = new my_class( func_get_args() );
}
echo "you can still create my_class instances like normal:";
$instance = new my_class( "one", "two", "three" );
echo "\n\n\n";
echo "but also through my_function:";
my_function( "one", "two", "three" );
Basically, you simply pass the result of func_get_args to the constructor of your class, and let it decide whether it is being called with an array of arguments from that function, or whether it is being called normally.
This code outputs
you can still create my_class instances like normal:
Param: one
Param: two
Param: three
but also through my_function:
Param: one
Param: two
Param: three
Hope that helps.
I've found here
Is there a call_user_func() equivalent to create a new class instance?
the example:
function createInstance($className, array $arguments = array())
{
if(class_exists($className)) {
return call_user_func_array(array(
new ReflectionClass($className), 'newInstance'),
$arguments);
}
return false;
}
But can somebody tell me if there is an example for classes with protected constructors?