Does PHP 7 have an equivalent of array_value_last()? - php

This is genuine question (but also code golf for PHP devs).
I know array_key_last() exists in PHP.
I would like to use array_value_last() on explode('/', __FILE__) but... array_value_last() doesn't exist.
I am working inside a constrained environment (an included file which contains and runs a function, before returning data) and I have tried both:
array_pop(explode('/', __FILE__))
end(explode('/', __FILE__))
and neither of these work. (I don't know why they are not working).
N.B. The sole purpose of the environment is to return a variable (either an array or a string). In this environment array_pop(explode('/', __FILE__)) and end(explode('/', __FILE__)) both result in a browser error: Content Encoding Error An error occurred during a connection to example.com. Please contact the website owners to inform them of this problem.
Statements such asechoand other executing statements produce the same Encoding Error.
Here is my current code, which is working:
$My_Filename = explode('/', __FILE__)[(count(explode('/', __FILE__)) - 1)];
Is there a shorthand in PHP 7 to get the last value of an array?

You could do it with end
$latestValue = end($array); // Returns latest value in $array, setting the internal pointer to the last element
reset($array); // Don't forget to reset the pointer!!!
Ok... if it doesn't work (that's very strange dude, big problem xD) you could try something like:
$aux = array_values($array); //No need to use this if it isn't an associative array
$size = count($aux);
$latestValue = $array[$size-1]; //Be careful with empty arrays

You can use basename(__FILE__); to get last part of the path. In general don't strive for this kind of one-liners - you won't gain anything in terms of performance, but loose code readability.
Both array_pop() and end() functions with expressions will give you a notice, because they will also try to modify variable (passed by reference) in current scope, and the message you get is coming from server or error handler (hidden details in production environment) - default interpreter display (better for dev) would give you: <b>Notice</b>: Only variables should be passed by reference in....

Here's a possible candidate for the code golf:
Original: explode('/', __FILE__)[(count(explode('/', __FILE__)) - 1)] // 59 characters
Alternative: array_reverse(explode('/', __FILE__))[0] // 40 characters
That represents a reduction of nearly 33%.
I'm curious to know if there might be an even better shorthand.

Related

Multiple procedure assignment for self variable in one line

Is there any way a variable can be assigned from multiple procedures in one line?
For example:
$class_splits = explode("\\", $class_name);
$short_class_name = $class_splits[count($class_splits) - 1] ?? null;
Translated to this pseudo code:
$short_class_name = explode("\\", $class_name) => prev_result(count(prev_result) -1);
I don't have big expectations on this as I know it looks too "high-level" but not sure if newer versions of PHP can handle this.
Thanks.
You can use an assignment as an expression, then refer to the variable that was assigned later in the containing expression.
$short_class_name = ($class_splits = explode("\\", $class_name))[count($class_splits) - 1] ?? null;
That said, I don't recommend coding like this. If the goal was to avoid creating another variable, it doesn't succeed at that. It just makes the whole thing more complicated and confusing.
I believe you have an "X/Y Problem": your actual requirement seems to be "how to split a string and return just the last element", but you've got stuck thinking about a particular solution to that.
As such, we can look at the answers to "How to get the last element of an array without deleting it?" To make it a one-line statement, we need something that a) does not require an argument by reference, and b) does not require the array to be mentioned twice.
A good candidate looks like array_slice, which can return a single-element array with just the last element, from which we can then extract the string with [0]:
$short_class_name = array_slice(explode("\\", $class_name), -1)[0];
Since we no longer need to call count(), we can avoid the problem of needing the same intermediate value in two places.
Whether the result is actually more readable than using two lines of code is a matter of taste - remember that a program is as much for human use as for machine use.

500 Internal Server Error Only variables should be passed by reference [duplicate]

// Other variables
$MAX_FILENAME_LENGTH = 260;
$file_name = $_FILES[$upload_name]['name'];
//echo "testing-".$file_name."<br>";
//$file_name = strtolower($file_name);
$file_extension = end(explode('.', $file_name)); //ERROR ON THIS LINE
$uploadErrors = array(
0=>'There is no error, the file uploaded with success',
1=>'The uploaded file exceeds the upload max filesize allowed.',
2=>'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
3=>'The uploaded file was only partially uploaded',
4=>'No file was uploaded',
6=>'Missing a temporary folder'
);
Any ideas? After 2 days still stuck.
Assign the result of explode to a variable and pass that variable to end:
$tmp = explode('.', $file_name);
$file_extension = end($tmp);
The problem is, that end requires a reference, because it modifies the internal representation of the array (i.e. it makes the current element pointer point to the last element).
The result of explode('.', $file_name) cannot be turned into a reference. This is a restriction in the PHP language, that probably exists for simplicity reasons.
Everyone else has already given you the reason you're getting an error, but here's the best way to do what you want to do:
$file_extension = pathinfo($file_name, PATHINFO_EXTENSION);
Php 7 compatible proper usage:
$fileName = 'long.file.name.jpg';
$tmp = explode('.', $fileName);
$fileExtension = end($tmp);
echo $fileExtension;
// jpg
save the array from explode() to a variable, and then call end() on this variable:
$tmp = explode('.', $file_name);
$file_extension = end($tmp);
btw: I use this code to get the file extension:
$ext = substr( strrchr($file_name, '.'), 1);
where strrchr extracts the string after the last . and substr cuts off the .
The answer given elsewhere,
$tmp = explode('.', $fileName);
$file_extension = end($tmp);
is correct and valid. It accomplishes what you are trying to do.
Why?
The end() function does not do quite what you think it does. This is related to how the PHP array data structure works. You don't normally see it, but arrays in PHP contain a pointer to a current element, which is used for iteration (like with foreach).
In order to use end(), you must have an actual array, which has attached to it (normally, invisibly), the current element pointer. The end() function physically modifies that pointer.
The output of explode() is not an actual array. It is a function output. Therefore, you cannot run end(explode()) because you violate language requirements.
Simply setting the output of explode() in a variable creates the array that you're looking for. That created array has a current element pointer. Now, all is once again right in the world.
So what about the parentheses?
This is not a bug. Once again, it's a language requirement.
The extra parentheses (like end((explode()))) do more than just grouping. They create an inline instance variable, just like setting the function output to a variable. You may think of it as a lambda function that is executed immediately.
This is another correct and valid solution. It is perhaps a better solution, as it takes less space. A good reviewer or maintainer should grok what you're trying to do when they see the extra parentheses.
If you use a linter or SCA program like PHPCS, that may dislike the extra parentheses, depending on the linting profile you're using. It's your linter, tell it what you want it to do for you.
Some other answers also list things like the spread operator or array_key_last(), which are also reasonable solutions. They may be perfectly valid but they're more complicated to use and read.
I'll just use the # prefix
This solution is valid, however incorrect. It is valid because it solves the problem. That's about the end of its merit.
Suppressing errors is always bad practice. There are many reasons why. One very large one is that you are trying to suppress one specific error condition (one that you have created), but the error suppression prefix suppresses all errors.
In this case, you will probably get away with this. However, engaging in bad programming habits is cheating and will likely lead you to cheat more and bigger in the future. You will be responsible for bad code. But I'm not the Code Police and it's your code. It's valid because it solves the problem.
Okay, so what's the best answer?
Do what #ryeguy suggests. Don't do string manipulation to solve a well-defined problem that the platform already solves for you. Use pathinfo().
This has the added benefit that it actually does what you want, which is finding the extension on a file name. There is a subtle difference.
What you are doing is getting the text following the final dot. This is different from finding the file extension. Consider the file name, .gitignore. PHP knows how to handle this. Does your code?
Once again, I'm not the Code Police. Do what suits you best.
Since it raise a flag for over 10 years, but works just fine and return the expected value, a little stfu operator is the goodiest bad practice you are all looking for:
$file_extension = #end(explode('.', $file_name));
But warning, don't use in loops due to a performance hit.
Newest version of php 7.3+ offer the method array_key_last() and array_key_first().
https://www.php.net/manual/en/function.array-key-last.php
uuuuuuu
uu$$$$$$$$$$$uu
uu$$$$$$$$$$$$$$$$$uu
u$$$$$$$$$$$$$$$$$$$$$u
u$$$$$$$$$$$$$$$$$$$$$$$u
u$$$$$$$$$$$$$$$$$$$$$$$$$u
u$$$$$$$$$$$$$$$$$$$$$$$$$u
u$$$$$$" "$$$" "$$$$$$u
"$$$$" u$u $$$$"
$$$u u$u u$$$
$$$u u$$$u u$$$
"$$$$uu$$$ $$$uu$$$$"
"$$$$$$$" "$$$$$$$"
u$$$$$$$u$$$$$$$u
u$"$"$"$"$"$"$u
uuu $$u$ $ $ $ $u$$ uuu
u$$$$ $$$$$u$u$u$$$ u$$$$
$$$$$uu "$$$$$$$$$" uu$$$$$$
u$$$$$$$$$$$uu """"" uuuu$$$$$$$$$$
$$$$"""$$$$$$$$$$uuu uu$$$$$$$$$"""$$$"
""" ""$$$$$$$$$$$uu ""$"""
uuuu ""$$$$$$$$$$uuu
u$$$uuu$$$$$$$$$uu ""$$$$$$$$$$$uuu$$$
$$$$$$$$$$"""" ""$$$$$$$$$$$"
"$$$$$" ""$$$$""
$$$" $$$$"
Try this:
$parts = explode('.', $file_name);
$file_extension = end($parts);
The reason is that the argument for end is passed by reference, since end modifies the array by advancing its internal pointer to the final element. If you're not passing a variable in, there's nothing for a reference to point to.
See end in the PHP manual for more info.
PHP complains because end() expects a reference to something that it wants to change (which can be a variable only). You however pass the result of explode() directly to end() without saving it to a variable first. At the moment when explode() returns your value, it exists only in memory and no variable points to it. You cannot create a reference to something (or to something unknown in the memory), that does not exists.
Or in other words: PHP does not know, if the value you give him is the direct value or just a pointer to the value (a pointer is also a variable (integer), which stores the offset of the memory, where the actual value resides). So PHP expects here a pointer (reference) always.
But since this is still just a notice (not even deprecated) in PHP 7, you can savely ignore notices and use the ignore-operator instead of completely deactivating error reporting for notices:
$file_extension = #end(explode('.', $file_name));
end(...[explode('.', $file_name)]) has worked since PHP 5.6. This is documented in the RFC although not in PHP docs themselves.
Just as you can't index the array immediately, you can't call end on it either. Assign it to a variable first, then call end.
$basenameAndExtension = explode('.', $file_name);
$ext = end($basenameAndExtension);
PHP offical Manual :
end()
Parameters
array
The array. This array is passed by reference because it is modified by the function. This means you must pass it a real variable and not a function returning an array because only actual variables may be passed by reference.
First, you will have to store the value in a variable like this
$value = explode("/", $string);
Then you can use the end function to get the last index from an array like this
echo end($value);
I hope it will work for you.

Strict Standards trouble using arrays and end() function [duplicate]

// Other variables
$MAX_FILENAME_LENGTH = 260;
$file_name = $_FILES[$upload_name]['name'];
//echo "testing-".$file_name."<br>";
//$file_name = strtolower($file_name);
$file_extension = end(explode('.', $file_name)); //ERROR ON THIS LINE
$uploadErrors = array(
0=>'There is no error, the file uploaded with success',
1=>'The uploaded file exceeds the upload max filesize allowed.',
2=>'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
3=>'The uploaded file was only partially uploaded',
4=>'No file was uploaded',
6=>'Missing a temporary folder'
);
Any ideas? After 2 days still stuck.
Assign the result of explode to a variable and pass that variable to end:
$tmp = explode('.', $file_name);
$file_extension = end($tmp);
The problem is, that end requires a reference, because it modifies the internal representation of the array (i.e. it makes the current element pointer point to the last element).
The result of explode('.', $file_name) cannot be turned into a reference. This is a restriction in the PHP language, that probably exists for simplicity reasons.
Everyone else has already given you the reason you're getting an error, but here's the best way to do what you want to do:
$file_extension = pathinfo($file_name, PATHINFO_EXTENSION);
Php 7 compatible proper usage:
$fileName = 'long.file.name.jpg';
$tmp = explode('.', $fileName);
$fileExtension = end($tmp);
echo $fileExtension;
// jpg
save the array from explode() to a variable, and then call end() on this variable:
$tmp = explode('.', $file_name);
$file_extension = end($tmp);
btw: I use this code to get the file extension:
$ext = substr( strrchr($file_name, '.'), 1);
where strrchr extracts the string after the last . and substr cuts off the .
The answer given elsewhere,
$tmp = explode('.', $fileName);
$file_extension = end($tmp);
is correct and valid. It accomplishes what you are trying to do.
Why?
The end() function does not do quite what you think it does. This is related to how the PHP array data structure works. You don't normally see it, but arrays in PHP contain a pointer to a current element, which is used for iteration (like with foreach).
In order to use end(), you must have an actual array, which has attached to it (normally, invisibly), the current element pointer. The end() function physically modifies that pointer.
The output of explode() is not an actual array. It is a function output. Therefore, you cannot run end(explode()) because you violate language requirements.
Simply setting the output of explode() in a variable creates the array that you're looking for. That created array has a current element pointer. Now, all is once again right in the world.
So what about the parentheses?
This is not a bug. Once again, it's a language requirement.
The extra parentheses (like end((explode()))) do more than just grouping. They create an inline instance variable, just like setting the function output to a variable. You may think of it as a lambda function that is executed immediately.
This is another correct and valid solution. It is perhaps a better solution, as it takes less space. A good reviewer or maintainer should grok what you're trying to do when they see the extra parentheses.
If you use a linter or SCA program like PHPCS, that may dislike the extra parentheses, depending on the linting profile you're using. It's your linter, tell it what you want it to do for you.
Some other answers also list things like the spread operator or array_key_last(), which are also reasonable solutions. They may be perfectly valid but they're more complicated to use and read.
I'll just use the # prefix
This solution is valid, however incorrect. It is valid because it solves the problem. That's about the end of its merit.
Suppressing errors is always bad practice. There are many reasons why. One very large one is that you are trying to suppress one specific error condition (one that you have created), but the error suppression prefix suppresses all errors.
In this case, you will probably get away with this. However, engaging in bad programming habits is cheating and will likely lead you to cheat more and bigger in the future. You will be responsible for bad code. But I'm not the Code Police and it's your code. It's valid because it solves the problem.
Okay, so what's the best answer?
Do what #ryeguy suggests. Don't do string manipulation to solve a well-defined problem that the platform already solves for you. Use pathinfo().
This has the added benefit that it actually does what you want, which is finding the extension on a file name. There is a subtle difference.
What you are doing is getting the text following the final dot. This is different from finding the file extension. Consider the file name, .gitignore. PHP knows how to handle this. Does your code?
Once again, I'm not the Code Police. Do what suits you best.
Since it raise a flag for over 10 years, but works just fine and return the expected value, a little stfu operator is the goodiest bad practice you are all looking for:
$file_extension = #end(explode('.', $file_name));
But warning, don't use in loops due to a performance hit.
Newest version of php 7.3+ offer the method array_key_last() and array_key_first().
https://www.php.net/manual/en/function.array-key-last.php
uuuuuuu
uu$$$$$$$$$$$uu
uu$$$$$$$$$$$$$$$$$uu
u$$$$$$$$$$$$$$$$$$$$$u
u$$$$$$$$$$$$$$$$$$$$$$$u
u$$$$$$$$$$$$$$$$$$$$$$$$$u
u$$$$$$$$$$$$$$$$$$$$$$$$$u
u$$$$$$" "$$$" "$$$$$$u
"$$$$" u$u $$$$"
$$$u u$u u$$$
$$$u u$$$u u$$$
"$$$$uu$$$ $$$uu$$$$"
"$$$$$$$" "$$$$$$$"
u$$$$$$$u$$$$$$$u
u$"$"$"$"$"$"$u
uuu $$u$ $ $ $ $u$$ uuu
u$$$$ $$$$$u$u$u$$$ u$$$$
$$$$$uu "$$$$$$$$$" uu$$$$$$
u$$$$$$$$$$$uu """"" uuuu$$$$$$$$$$
$$$$"""$$$$$$$$$$uuu uu$$$$$$$$$"""$$$"
""" ""$$$$$$$$$$$uu ""$"""
uuuu ""$$$$$$$$$$uuu
u$$$uuu$$$$$$$$$uu ""$$$$$$$$$$$uuu$$$
$$$$$$$$$$"""" ""$$$$$$$$$$$"
"$$$$$" ""$$$$""
$$$" $$$$"
Try this:
$parts = explode('.', $file_name);
$file_extension = end($parts);
The reason is that the argument for end is passed by reference, since end modifies the array by advancing its internal pointer to the final element. If you're not passing a variable in, there's nothing for a reference to point to.
See end in the PHP manual for more info.
PHP complains because end() expects a reference to something that it wants to change (which can be a variable only). You however pass the result of explode() directly to end() without saving it to a variable first. At the moment when explode() returns your value, it exists only in memory and no variable points to it. You cannot create a reference to something (or to something unknown in the memory), that does not exists.
Or in other words: PHP does not know, if the value you give him is the direct value or just a pointer to the value (a pointer is also a variable (integer), which stores the offset of the memory, where the actual value resides). So PHP expects here a pointer (reference) always.
But since this is still just a notice (not even deprecated) in PHP 7, you can savely ignore notices and use the ignore-operator instead of completely deactivating error reporting for notices:
$file_extension = #end(explode('.', $file_name));
end(...[explode('.', $file_name)]) has worked since PHP 5.6. This is documented in the RFC although not in PHP docs themselves.
Just as you can't index the array immediately, you can't call end on it either. Assign it to a variable first, then call end.
$basenameAndExtension = explode('.', $file_name);
$ext = end($basenameAndExtension);
PHP offical Manual :
end()
Parameters
array
The array. This array is passed by reference because it is modified by the function. This means you must pass it a real variable and not a function returning an array because only actual variables may be passed by reference.
First, you will have to store the value in a variable like this
$value = explode("/", $string);
Then you can use the end function to get the last index from an array like this
echo end($value);
I hope it will work for you.

Avoid a "PHP Strict standards" warning with parentheses? [duplicate]

It was noted in another question that wrapping the result of a PHP function call in parentheses can somehow convert the result into a fully-fledged expression, such that the following works:
<?php
error_reporting(E_ALL | E_STRICT);
function get_array() {
return array();
}
function foo() {
// return reset(get_array());
// ^ error: "Only variables should be passed by reference"
return reset((get_array()));
// ^ OK
}
foo();
I'm trying to find anything in the documentation to explicitly and unambiguously explain what is happening here. Unlike in C++, I don't know enough about the PHP grammar and its treatment of statements/expressions to derive it myself.
Is there anything hidden in the documentation regarding this behaviour? If not, can somebody else explain it without resorting to supposition?
Update
I first found this EBNF purporting to represent the PHP grammar, and tried to decode my scripts myself, but eventually gave up.
Then, using phc to generate a .dot file of the two foo() variants, I produced AST images for both scripts using the following commands:
$ yum install phc graphviz
$ phc --dump-ast-dot test1.php > test1.dot
$ dot -Tpng test1.dot > test1.png
$ phc --dump-ast-dot test2.php > test2.dot
$ dot -Tpng test2.dot > test2.png
In both cases the result was exactly the same:
This behavior could be classified as bug, so you should definitely not rely on it.
The (simplified) conditions for the message not to be thrown on a function call are as follows (see the definition of the opcode ZEND_SEND_VAR_NO_REF):
the argument is not a function call (or if it is, it returns by reference), and
the argument is either a reference or it has reference count 1 (if it has reference count 1, it's turned into a reference).
Let's analyze these in more detail.
First point is true (not a function call)
Due to the additional parentheses, PHP no longer detects that the argument is a function call.
When parsing a non empty function argument list there are three possibilities for PHP:
An expr_without_variable
A variable
(A & followed by a variable, for the removed call-time pass by reference feature)
When writing just get_array() PHP sees this as a variable.
(get_array()) on the other hand does not qualify as a variable. It is an expr_without_variable.
This ultimately affects the way the code compiles, namely the extended value of the opcode SEND_VAR_NO_REF will no longer include the flag ZEND_ARG_SEND_FUNCTION, which is the way the function call is detected in the opcode implementation.
Second point is true (the reference count is 1)
At several points, the Zend Engine allows non-references with reference count 1 where references are expected. These details should not be exposed to the user, but unfortunately they are here.
In your example you're returning an array that's not referenced from anywhere else. If it were, you would still get the message, i.e. this second point would not be true.
So the following very similar example does not work:
<?php
$a = array();
function get_array() {
return $GLOBALS['a'];
}
return reset((get_array()));
A) To understand what's happening here, one needs to understand PHP's handling of values/variables and references (PDF, 1.2MB). As stated throughout the documentation: "references are not pointers"; and you can only return variables by reference from a function - nothing else.
In my opinion, that means, any function in PHP will return a reference. But some functions (built in PHP) require values/variables as arguments. Now, if you are nesting function-calls, the inner one returns a reference, while the outer one expects a value. This leads to the 'famous' E_STRICT-error "Only variables should be passed by reference".
$fileName = 'example.txt';
$fileExtension = array_pop(explode('.', $fileName));
// will result in Error 2048: Only variables should be passed by reference in…
B) I found a line in the PHP-syntax description linked in the question.
expr_without_variable = "(" expr ")"
In combination with this sentence from the documentation: "In PHP, almost anything you write is an expression. The simplest yet most accurate way to define an expression is 'anything that has a value'.", this leads me to the conclusion that even (5) is an expression in PHP, which evaluates to an integer with the value 5.
(As $a = 5 is not only an assignment but also an expression, which evalutes to 5.)
Conclusion
If you pass a reference to the expression (...), this expression will return a value, which then may be passed as argument to the outer function. If that (my line of thought) is true, the following two lines should work equivalently:
// what I've used over years: (spaces only added for readability)
$fileExtension = array_pop( ( explode('.', $fileName) ) );
// vs
$fileExtension = array_pop( $tmp = explode('.', $fileName) );
See also PHP 5.0.5: Fatal error: Only variables can be passed by reference; 13.09.2005

PHP error - Only variables should be passed by reference [duplicate]

// Other variables
$MAX_FILENAME_LENGTH = 260;
$file_name = $_FILES[$upload_name]['name'];
//echo "testing-".$file_name."<br>";
//$file_name = strtolower($file_name);
$file_extension = end(explode('.', $file_name)); //ERROR ON THIS LINE
$uploadErrors = array(
0=>'There is no error, the file uploaded with success',
1=>'The uploaded file exceeds the upload max filesize allowed.',
2=>'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
3=>'The uploaded file was only partially uploaded',
4=>'No file was uploaded',
6=>'Missing a temporary folder'
);
Any ideas? After 2 days still stuck.
Assign the result of explode to a variable and pass that variable to end:
$tmp = explode('.', $file_name);
$file_extension = end($tmp);
The problem is, that end requires a reference, because it modifies the internal representation of the array (i.e. it makes the current element pointer point to the last element).
The result of explode('.', $file_name) cannot be turned into a reference. This is a restriction in the PHP language, that probably exists for simplicity reasons.
Everyone else has already given you the reason you're getting an error, but here's the best way to do what you want to do:
$file_extension = pathinfo($file_name, PATHINFO_EXTENSION);
Php 7 compatible proper usage:
$fileName = 'long.file.name.jpg';
$tmp = explode('.', $fileName);
$fileExtension = end($tmp);
echo $fileExtension;
// jpg
save the array from explode() to a variable, and then call end() on this variable:
$tmp = explode('.', $file_name);
$file_extension = end($tmp);
btw: I use this code to get the file extension:
$ext = substr( strrchr($file_name, '.'), 1);
where strrchr extracts the string after the last . and substr cuts off the .
The answer given elsewhere,
$tmp = explode('.', $fileName);
$file_extension = end($tmp);
is correct and valid. It accomplishes what you are trying to do.
Why?
The end() function does not do quite what you think it does. This is related to how the PHP array data structure works. You don't normally see it, but arrays in PHP contain a pointer to a current element, which is used for iteration (like with foreach).
In order to use end(), you must have an actual array, which has attached to it (normally, invisibly), the current element pointer. The end() function physically modifies that pointer.
The output of explode() is not an actual array. It is a function output. Therefore, you cannot run end(explode()) because you violate language requirements.
Simply setting the output of explode() in a variable creates the array that you're looking for. That created array has a current element pointer. Now, all is once again right in the world.
So what about the parentheses?
This is not a bug. Once again, it's a language requirement.
The extra parentheses (like end((explode()))) do more than just grouping. They create an inline instance variable, just like setting the function output to a variable. You may think of it as a lambda function that is executed immediately.
This is another correct and valid solution. It is perhaps a better solution, as it takes less space. A good reviewer or maintainer should grok what you're trying to do when they see the extra parentheses.
If you use a linter or SCA program like PHPCS, that may dislike the extra parentheses, depending on the linting profile you're using. It's your linter, tell it what you want it to do for you.
Some other answers also list things like the spread operator or array_key_last(), which are also reasonable solutions. They may be perfectly valid but they're more complicated to use and read.
I'll just use the # prefix
This solution is valid, however incorrect. It is valid because it solves the problem. That's about the end of its merit.
Suppressing errors is always bad practice. There are many reasons why. One very large one is that you are trying to suppress one specific error condition (one that you have created), but the error suppression prefix suppresses all errors.
In this case, you will probably get away with this. However, engaging in bad programming habits is cheating and will likely lead you to cheat more and bigger in the future. You will be responsible for bad code. But I'm not the Code Police and it's your code. It's valid because it solves the problem.
Okay, so what's the best answer?
Do what #ryeguy suggests. Don't do string manipulation to solve a well-defined problem that the platform already solves for you. Use pathinfo().
This has the added benefit that it actually does what you want, which is finding the extension on a file name. There is a subtle difference.
What you are doing is getting the text following the final dot. This is different from finding the file extension. Consider the file name, .gitignore. PHP knows how to handle this. Does your code?
Once again, I'm not the Code Police. Do what suits you best.
Since it raise a flag for over 10 years, but works just fine and return the expected value, a little stfu operator is the goodiest bad practice you are all looking for:
$file_extension = #end(explode('.', $file_name));
But warning, don't use in loops due to a performance hit.
Newest version of php 7.3+ offer the method array_key_last() and array_key_first().
https://www.php.net/manual/en/function.array-key-last.php
uuuuuuu
uu$$$$$$$$$$$uu
uu$$$$$$$$$$$$$$$$$uu
u$$$$$$$$$$$$$$$$$$$$$u
u$$$$$$$$$$$$$$$$$$$$$$$u
u$$$$$$$$$$$$$$$$$$$$$$$$$u
u$$$$$$$$$$$$$$$$$$$$$$$$$u
u$$$$$$" "$$$" "$$$$$$u
"$$$$" u$u $$$$"
$$$u u$u u$$$
$$$u u$$$u u$$$
"$$$$uu$$$ $$$uu$$$$"
"$$$$$$$" "$$$$$$$"
u$$$$$$$u$$$$$$$u
u$"$"$"$"$"$"$u
uuu $$u$ $ $ $ $u$$ uuu
u$$$$ $$$$$u$u$u$$$ u$$$$
$$$$$uu "$$$$$$$$$" uu$$$$$$
u$$$$$$$$$$$uu """"" uuuu$$$$$$$$$$
$$$$"""$$$$$$$$$$uuu uu$$$$$$$$$"""$$$"
""" ""$$$$$$$$$$$uu ""$"""
uuuu ""$$$$$$$$$$uuu
u$$$uuu$$$$$$$$$uu ""$$$$$$$$$$$uuu$$$
$$$$$$$$$$"""" ""$$$$$$$$$$$"
"$$$$$" ""$$$$""
$$$" $$$$"
Try this:
$parts = explode('.', $file_name);
$file_extension = end($parts);
The reason is that the argument for end is passed by reference, since end modifies the array by advancing its internal pointer to the final element. If you're not passing a variable in, there's nothing for a reference to point to.
See end in the PHP manual for more info.
PHP complains because end() expects a reference to something that it wants to change (which can be a variable only). You however pass the result of explode() directly to end() without saving it to a variable first. At the moment when explode() returns your value, it exists only in memory and no variable points to it. You cannot create a reference to something (or to something unknown in the memory), that does not exists.
Or in other words: PHP does not know, if the value you give him is the direct value or just a pointer to the value (a pointer is also a variable (integer), which stores the offset of the memory, where the actual value resides). So PHP expects here a pointer (reference) always.
But since this is still just a notice (not even deprecated) in PHP 7, you can savely ignore notices and use the ignore-operator instead of completely deactivating error reporting for notices:
$file_extension = #end(explode('.', $file_name));
end(...[explode('.', $file_name)]) has worked since PHP 5.6. This is documented in the RFC although not in PHP docs themselves.
Just as you can't index the array immediately, you can't call end on it either. Assign it to a variable first, then call end.
$basenameAndExtension = explode('.', $file_name);
$ext = end($basenameAndExtension);
PHP offical Manual :
end()
Parameters
array
The array. This array is passed by reference because it is modified by the function. This means you must pass it a real variable and not a function returning an array because only actual variables may be passed by reference.
First, you will have to store the value in a variable like this
$value = explode("/", $string);
Then you can use the end function to get the last index from an array like this
echo end($value);
I hope it will work for you.

Categories