this package is a collection of various helpers for string manipulation, validation, and utility functions designed to simplify the life of php developers. it streamlines tasks like checking variable existence, comparing values, and handling dates, urls, and emails. this tool enhances efficiency by offering concise, reusable methods for everyday coding challenges.
composer require vielhuber/stringhelper
// check existence
if (__x($var)) {
}
if (__x(@$var)) {
}
// check non-existence
if (__nx($var)) {
}
if (__nx(@$var)) {
}
// check existence (without stfu-operator)
if (__rx($var)) {
}
if (__fx(fn() => $var)) {
}
// check non-existence (without stfu-operator)
if (__rnx($var)) {
}
if (__fnx(fn() => $var)) {
}
// php has a lot of pitfalls, when comparing loosely
if( 0 == 'true' ) // true
if( 0 == 'str' ) // true
if( 'null' == null ) // false
if( '0' == null ) // false
if( '0' == true ) // false
if( '0' == false ) // true
if( 'false' == true ) // true
if( 'false' == false ) // false
if( new stdClass == true ) // true
if( [] == false ) // true
if( [] == null ) // true
if( [''] == [] ) // false
if( [''] == [0] ) // true
if( 0 == '' ) // true
if( 0 == ' ' ) // true
if( -1 == true ) // true
if( '-1' == true ) // true
// this non-strict equality is symmetric, but not transitive
$a = ''; $b = 0; $c = 'oh';
$a == $b; // true
$b == $c; // true
$c == $a; // false
// to overcome this issue, we...
// ...use strict comparison when possible
if( $var === 'foo' )
{
}
// ...use loose comparison when appropriate
if( $_GET['number'] == 1337 )
{
}
// ...check for truthness / falsiness with these helper methods
if( __true($var) )
{
}
if( __false($var) )
{
}
// be aware, that __true is not always the logic negation of __false
__true(null) // false
__false(null) // false
// get variable if exists, otherwise null
__v( $var )
// get variable if exists, otherwise 'default'
__v( $var, 'default' )
// get first variable that exists, otherwise null
__v( $var1, $var2, $var3 )
// get variable if exists, otherwise the empty object
__e( $var )
__e( $var, 'default' )
__e( $var1, $var2, $var3 )
// loop only if exists
foreach (__e($array) as $array__key => $array__value) {
}
// if you are unsure, if a variable is even set before checking its existence,
// simply prefix it with the stfu-operator @
if( __x(@$var) )
if( __nx(@$var) )
if( __true(@$var) )
if( __false(@$var) )
if( @$var === 'foo' )
if( @$_GET['number'] == 1337 )
echo __v(@$var)
foreach( __e(@$array) as $array__key=>$array__value)
A short note on the usage of @: In this concept we use @-operator that hides errors. We are aware of its potential misuse and also of its benefits.
Be careful when using @$a['undefined'], there can be 2 possible errors: a missing variable or a missing index. In both cases, we intentionally prevent the parser from stopping and catch the resulting null value. Be aware: If $a is a string, @$a['undefined'] evaluates to $a[0] since php coerces 'undefined' to 0 and therefore exists.
Another general rule of thumb: Don't use the operator before function calls (@__x($a['undefined']).
A caveat is that the @-operator does not catch any fatal runtime errors since PHP 8 anymore.
For that there is also another more sophisticated way of checking the existence of variables:
If $var
is totally undefined, the following expressions evaluate correctly to false:
__fx(fn()=>$var)
__fx(fn()=>$var['foo']['bar']['baz'])
__fx(fn()=>$var())
Be aware that arrow functions are only available from php 7.4; Prior versions should use:
__fx(function () use (&$var) {
return $var['foo']['bar']['baz'];
});
Another approach is to pass (potentially undefined) variables by reference to the rx
/nrx
-helpers:
__rx($var) // false
__rx($var['foo']['bar']['baz']) // false
__nrx($var) // true
Be aware that undefined variables are defined as null by php after the check:
array_key_exists('foo', get_defined_vars()); // false
__rx($foo);
array_key_exists('foo', get_defined_vars()); // true
// consider the following laravelish code
class Person
{
public $id;
function __construct($id)
{
$this->id = $id;
}
static function find($id)
{
// mock example (normally lookup in database)
if( $id === 1 || $id === 2 )
{
return new Person($id);
}
else
{
return null;
}
}
function getAddress()
{
if( $this->id === 1 )
{
return new Address();
}
else
{
return null;
}
}
}
class Address
{
function getCountry()
{
return new Country();
}
}
class Country
{
function getName()
{
return 'Germany';
}
}
echo Person::find(1)->getAddress()->getCountry()->getName(); // 'Germany'
echo Person::find(2)->getAddress()->getCountry()->getName(); // fails because person with id 2 has no address
echo Person::find(3)->getAddress()->getCountry()->getName(); // fails because person with id 3 does not even exist
// due to the fact that the null propagating method call operator
// (https://wiki.php.net/rfc/nullsafe_calls) is still a rfc, we cannot write
echo Person::find(3)?->getAddress()?->getCountry()?->getName(); // null
// we therefore return a null model object
class Person
{
public $id;
function __construct($id)
{
$this->id = $id;
}
static function find($id)
{
if( $id === 1 || $id === 2 )
{
return new Person($id);
}
else
{
return __empty();
}
}
function getAddress()
{
if( $this->id === 1 )
{
return new Address();
}
else
{
return __empty();
}
}
}
class Address
{
function getCountry()
{
return new Country();
}
}
class Country
{
function getName()
{
return 'Germany';
}
}
// this empty helper object is quite useful for returning an empty class which is callable with undefined functions
__empty()
// we can no conveniently call those chains...
echo Person::find(1)->getAddress()->getCountry()->getName(); // 'Germany'
echo Person::find(2)->getAddress()->getCountry()->getName(); // ''
echo Person::find(3)->getAddress()->getCountry()->getName(); // ''
// ...check for existence...
if( __x(Person::find(1)->getAddress()->getCountry()->getName()) )
{
}
// ...check for strict equality...
if( Person::find(1)->getAddress()->getCountry()->getName() === 'Germany' )
{
}
// ...get a value...
echo __v( Person::find(1)->getAddress()->getCountry()->getName(), 'default' );
// ...and loop when possible
foreach( Person::find(1)->getAddress()->getCountry() as $value )
{
}