I'm trying to take two lines of code from an elseif statement and create a function that returns the parameters back to the parent function. It's a simple card game that searches my $Cards array for a three of a kind. Here's the original code:
elseif(count($Cards) == 3) {
$CardsNotOfValue = $this->_getCardsNotOfFaceValue($faceValue, $CardsGroupedByValues);
list($Kicker1, $Kicker2) = $this->_getSortedCards($CardsNotOfValue);
return new ThreeOfAKind(array_merge($Cards, array($Kicker1, $Kicker2)));
}
Thus far, my code looks like this:
function { if (count($Cards) == 3) {
**LINE 36** $Kicker = $this->kickerCards($faceValue, $CardsGroupedByValues); }
**LINE 55** public function kickerCards(array $kickers)
{
$CardsNotOfValue = $this->_getCardsNotOfFaceValue($faceValue, $CardsGroupedByValues);
return $this->_getSortedCards($CardsNotOfValue);
}
When I try to execute a four of a kind, I get the following error (I tried to highlight the lines in question above):
PHP Catchable fatal error: Argument 1 passed to BestHandIdentifier::kickerCards() must be an array, integer given, called in /home/dev/parameter2/BestHandIdentifier.php on line 36 and defined in /home/dev/parameter2/BestHandIdentifier.php on line 55
I'm having a bit of trouble understanding how to create ($faceValue, $CardsGroupedByValues) and pass an array for my new function to evaluate. Have I gone too far in the wrong direction to begin with?
Your function definition is:
public function kickerCards(array $kickers);
So $kickers must be an array...
You are trying to call the function with:
$this->kickerCards($faceValue, $CardsGroupedByValues);
Passing two arguments, the $faceValue which is an integer, 2nd argument is an array.
Your function definition should look like:
public function kickerCards($faceValue, array $cards);
If I could elaborate further, making some assumptions.
My assumptions:
The function take a face value and array of cards currently held
The return of the function should be the cards in that array that do not match the face values.
The Cards are an array with a value (and possibly suit) key. e.g.
$twoOfHearts = array('value'=>2,'suit'=>'hearts');
So here's a possible implementation
public function kickerCards($faceValue, array $cards) {
$kickerCards = array();
foreach($cards as $card) {
if ($card['value'] != $faceValue)
$kickerCards[] = $card;
}
return $kickerCards;
}
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.
It can be done by passing the function name in a string PHP pass function as param then call the function?
Well that is very crude.
No type checking
If I refactor the function name the string containing the variable need to be fixed too manually. If we have a typo it won't be checked on compile time.
It's not like in vb.net where we have addressOf operator.
Is this really the only way to do this in PhP?
I mean the lamda function seems more sane. At least the variable we pass is really a functio6 and not a string.
Am I wrong here?
Is the right way to do this is to use lambda?
Or is there any other way?
I can use closures like this
function getSelectedElements($textFile)
{
$standardfuncline2= function (&$arout,$line)
{
standardfuncline1 ($arout,$line);
};
$result = getSelectedElementsCustomFunc ($textFile,$standardfuncline2);
return $result;
}
instead of
$result = getSelectedElementsCustomFunc ($textFile,"standardfuncline1");
That seems to be more proven with all type checking and stuffs. However, kind of too long isn't it?
You can define your function as a closure, i.e. an anonymous function which can be assigned to a variable or passed as a function argument directly. The following example is taken from the PHP docs on callables:
Callback example using a Closure
<?php
// Our closure
$double = function($a) {
return $a * 2;
};
// This is our range of numbers
$numbers = range(1, 5);
// Use the closure as a callback here to
// double the size of each element in our
// range
$new_numbers = array_map($double, $numbers);
print implode(' ', $new_numbers);
?>
The above example will output:
2 4 6 8 10
More variants on the above can be found in the PHP documentation on anonymous functions.
When referencing an existing function
There is no such solution for functions that are defined in the usual way, but you can encapsulate them as a Callable:
// Your already existing function:
function myFunc($arg) {
echo "running myFunc with '$arg'.";
}
// The new Callable wrapper for it:
$myFunc = function ($arg) {
myFunc($arg);
};
// Calling it (same as in first solution)
call_user_func($myFunc, 'test');
You can sure do some Type-Hinting even when using call_user_func() like so:
/**
* #var $arrActions array
* #return mixed
*/
function doSomething(array $arrActions) { // TYPE HINT ARRAY
$output = "";
if(is_array($arrActions)) {
foreach ($arrActions as $action) {
$output .= "Have you already performed Action Nr. $action ?\n";
}
}
return $output;
}
// CALL WITH ARRAY AS ARGUMENT..
var_dump( call_user_func('doSomething', ["one", "two", "three"]) );
// PRODUCES:
string 'Have you already performed Action Nr. one ?
Have you already performed Action Nr. two ?
Have you already performed Action Nr. three ?
' (length=134)
// CALL WITH STRING AS ARGUMENT..
var_dump( call_user_func('doSomething', "one"]) );
// PRODUCES:
Fatal error: Uncaught TypeError: Argument 1 passed to doSomething() must be of the type array, string given....
I'm looking to figure out how to add more arguments to a function call based on an Array and can't figure out what I need to do. The function in question doesn't work with simply passing an array, but the array has to explode somehow as if each array element was a new argument in the function call. I don't think call_user_func_array works but perhaps I don't know how to execute it properly. To give some context, the array of arguments are coming from a varying amount of $_GET arguments which is processed by an API class file I have no control over, but it appears that I can add a lot of arguments that allow the results to filter.
$arrayofarguments = array("dynamicarg1","dynamicarg2","dynamicarg3");
$runthis = example($staticargument1,
$staticargument2,
$staticargument3,
$arrayofarguments,
$staticargument4);
//run the results
echo $runthis;
Expected result
$runthis = example($staticargument1,
$staticargument2,
$staticargument3,
"dynamicarg1",
"dynamicarg2",
"dynamicarg3",
$staticargument4);
Thanks for the help! :)
I think you have to do something like
function example("blaa","foo","bar",$arrayofarguments,"test") {
$args = func_get_args();
// $arg[3] would be $arrayofarguments
foreach ( $arg[3] as $function) {
$function(); // this calls the function
}
}
I have the following class with several properties and a method in PHP (This is simplified code).
class Member{
public $Name;
public $Family;
public function Fetch_Name(){
for($i=0;$i<10;$i++){
$this[$i]->$Name = I find the name using RegExp and return the value to be stored here;
$this[$i]->Family = I find the family using RegExp and return the value to be stored here;
}
}//function
}//class
In the function Fetch_Name(), I want to find all the names and families that is in a text file using RegExp and store them as properties of object in the form of an array. But I don't know how should I define an array of the Member. Is it logical or I should define StdClass or 2-dimension array instead of class?
I found slightly similar discussion here, but a 2 dimensional array is used instead of storing data in the object using class properties.
I think my problem is in defining the following lines of code.
$Member = new Member();
$Member->Fetch_name();
The member that I have defined is not an array. If I do define it array, still it does not work. I did this
$Member[]= new Member();
But it gives error
Fatal error: Call to a member function Fetch_name() on a non-object in
if I give $Member[0]= new Member() then I don't know how to make $Member1 or Member[2] or so forth in the Fetch_Name function. I hope my question is not complex and illogical.
Many thanks in advance
A Member object represents one member. You're trying to overload it to represent or handle many members, which doesn't really make sense. In the end you'll want to end up with an array that holds many Member instances, not the other way around:
$members = array();
for (...) {
$members[] = new Member($name, $family);
}
Most likely you don't really need your Member class to do anything really; the extraction logic should reside outside of the Member class, perhaps in an Extractor class or something similar. From the outside, your code should likely look like this:
$parser = new TextFileParser('my_file.txt');
$members = $parser->extractMembers();
I think you should have two classes :
The first one, Fetcher (or call it as you like), with your function.
The second one, Member, with the properties Name and Family.
It is not the job of a Member to fetch in your text, that's why I would make another class.
In your function, do your job, and in the loop, do this :
for($i = 0; $i < 10; ++$i){
$member = new Member();
$member->setName($name);
$member->setFamily($family);
// The following is an example, do what you want with the generated Member
$this->members[$i] = $member;
}
The problem here is that you are not using the object of type Member as array correctly. The correct format of your code would be:
class Member{
public $Name;
public $Family;
public function Fetch_Name(){
for($i=0;$i<10;$i++){
$this->Name[$i] = 'I find the name using RegExp and return the value to be stored here';
$this->Family[$i] = 'I find the family using RegExp and return the value to be stored here';
}
}
}
First, $this->Name not $this->$Name because Name is already declared as a member variable and $this->Name[$i] is the correct syntax because $this reference to the current object, it cannot be converted to array, as itself. The array must be contained in the member variable.
L.E: I might add that You are not writing your code according to PHP naming standards. This does not affect your functionality, but it is good practice to write your code in the standard way. After all, there is a purpose of having a standard.
Here you have a guide on how to do that.
And I would write your code like this:
class Member{
public $name;
public $family;
public function fetchName(){
for($i=0;$i<10;$i++){
$this->name[$i] = 'I find the name using RegExp and return the value to be stored here';
$this->family[$i] = 'I find the family using RegExp and return the value to be stored here';
}
}
}
L.E2: Seeing what you comented above, I will modify my answer like this:
So you are saying that you have an object of which values must be stored into an array, after the call. Well, after is the key word here:
Initialize your object var:
$member = new Memeber();
$memebr->fechNames();
Initialize and array in foreach
$Member = new Member();
foreach ($Member->Name as $member_name){
$array['names'][] = $member_name;
}
foreach ($Member->Family as $member_family) {
$array['family'][] = $member_family;
}
var_dump($array);
Is this more of what you wanted?
Hope it helps!
Keep on coding!
Ares.
while reading abt array_filter() from php manual,came to face example to demostrate
the same function using callback function as given below
<?php
function odd($var)
{
// returns whether the input integer is odd
return($var & 1);
}
function even($var)
{
// returns whether the input integer is even
return(!($var & 1));
}
$array1 = array("a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5);
$array2 = array(6, 7, 8, 9, 10, 11, 12);
echo "Odd :\n";
print_r(array_filter($array1, "odd"));
echo "Even:\n";
print_r(array_filter($array2, "even"));
?>
can you please help me to know how actually calback function calling,actual parameter pass,working?
any link to demostrate about callback wld be great help.
In the two given examples, array_filter will go over the values in the passed array and send each value in it to the callback function (odd or even). The callback function will then inspect the value to see whether it is odd or even and return TRUE or FALSE. If it returns FALSE, the value is filtered from the array.
The easiest way to find out what your function is passing to your callback is to supply a callback that prints the passed arguments, e.g.
array_filter($anArray, function() { var_dump(func_get_args()) });
Callbacks are described in detail at
http://de.php.net/manual/en/language.pseudo-types.php#language.types.callback
Imagine you have a function like this:
function getNumbersDivisibleBy3($arr)
{
$threes = array();
foreach($arr as $val)
{
if($val % 3 == 0)
{
$threes[] = $val;
}
}
return $threes
}
This function filters out all the numbers divisible by three from an array and returns them as another array.
Now imagine another function:
function GetWordsStartingWithC($arr)
{
$cs = array();
foreach($arr as $word)
{
if($word[0] == 'C')
{
$cs[] = $word;
}
}
return $cs;
}
This function filters out all the words that start with C from an array of words and returns them another array.
If you look at the above functions, their meta function (as it were) can be explained as "This functions filters out all the items in an array that satisfies a condition and returns them as another array."
So instead of having to write the same boiler plate code to iterate through a list and filter out all elements that match, the PHP developers have written a function that takes an array and a string that is a function name.
In other languages, such as C#, instead of a string that is a function name, you actually pass in an object called a delegate, which is a pointer or reference to a function. But in PHP they have ways of figuring out which function you mean by the name you pass in. I don't know what those are.
So the array_filter function could look something like this (it won't as it's probably not written in PHP)
function array_filter($arr, $callbackname)
{
$result = array();
foreach($arr as $item)
{
if(call_user_func($callbackname, $item))
{
$result[] = $item;
}
}
return $result;
}
In that function you can see how similar it is to the previous two, but instead of a predefined condition, it calls back (using the call_user_func() function) the function to be used via the name you passed in and applies it to each item in the array by using each item as a parameter for the function.
So you can reduce the amount of code you write by using array_filter because you don't have to write the boiler plate iteration code, just the conditional function you need to filter on.
A callback function is a function that it "called back" by another one. In the case of array_filter() the callback is invoked for every element of the array, and that element is the argument passed to it. You don't control what argument are passed, that's up the the main function you're using.
So you basically say to array_filter(): please run through this array and apply this function named "odd" to every element; this function will return a boolean value so you know what to keep and what to discard.