Pretty much all my class methods start the same way, by checking to see if the arguments passed are empty or not (variations for where I am expecting bools and int-0's)
Is there a less repetitive way of checking the values?
public function updateproduct($product, $storeid) {
if ( empty($product) || empty($storeid) ) {
return false;
}
// do stuff
}
Using func_num_args to iterate over an array of arg values returned by func_get_args is one way to accomplish what you are after
function foo($numargs, $arg_list) {
for ($i = 0; $i < $numargs; $i++) {
if (empty($arg_list[i])) {
return false;
}
}
return true;
}
function bar($arg1, $arg2) {
if (!foo(func_num_args(), func_get_args())) {
//...
}
}
bar('baz', null);
This function tests to see if any of the arguments passed to it are empty. The upside is the simplicity. The downside is that it does not short-circuit if an empty value is found.
I imagine if you were to notice the impact of it not short-circuiting, you are sending too many params to your function.
function anyEmpty(...$args){
return array_filter($args) !== $args;
}
Then our usage in updateProduct function:
function updateProduct($product, $storeId){
if (anyEmpty($product, $storeId)) {
return False;
}
//do your stuff
return True;
}
Or alternatively, if you would prefer to specify the params dynamically:
if (anyEmpty(...func_get_args())) {
return False;
}
Related
Suppose you have a class that can be instantiated by a null value or an int variable. Now, you want to make most of it's methods to return null immediately if that instantiating variable is null otherwise each method will run its necessary logic, that class would look something like this:
function get_number_from_int($int) {
if (1 === $int) {
return 'one';
}
return 'dunno';
}
class Test {
protected ?int $null_or_int = null;
public function __construct($null_or_int) {
$this->null_or_int = $null_or_int;
}
public function get_number_name() : ?string {
if (null === $this->null_or_int) {
return null;
}
return get_number_from_int($this->null_or_int);
}
public function is_it_one() : ?bool {
if (null === $this->null_or_int) {
return null;
}
return ($this->null_or_int === 1);
}
}
var_dump((new Test(1))->get_number_name());
var_dump((new Test(1))->is_it_one());
var_dump((new Test(null))->get_number_name());
var_dump((new Test(null))->is_it_one());
Then it will return the following results as expected:
string(3) "one"
bool(true)
NULL
NULL
But notice that we have so many repeats of
if (null === $this->null_or_int) {
return null;
}
on each of our method.
Is there a possible way that we can immediately bail out or return the result of another method if that method has a return value, say:
private function return_null_if_not_int() {
if (null === $this->null_or_int) {
return null;
}
}
^ so this function will return null if it's validation condition is met, otherwise it won't return anything/void
so, ideally on each of our methods, instead of repeating that 3 line if-statement, we can simply:
public function get_number_name() : ?string {
$this->return_null_if_not_int();
return get_number_from_int($this->null_or_int);
}
and
public function is_it_one() : ?bool {
$this->return_null_if_not_int();
return ($this->null_or_int === 1);
}
^ so that if that validation method returns something, it will return that instead, otherwise, it will proceed with the rest of the logic of that method.
The above examples obvious won't work, though it runs that validation method, it will still proceed with processing the rest of the method's code.
Is there a more elegant way to do this, something that will reduce the amount of repeats?
Thank you!
You could mark your methods as private and access them though the __call() magic method:
private function someMethod(){
return 'always something usefull';
}
function __call( $method_name ){
return (
is_null($this->null_or_int)
? null
: $this->$method_name()
);
}
Note that this approach is usually considered as a bad practice and have some impact on performance.
I've wanted to avoid blowing the stack while creating a system similar to function advice or method combination. This involves tree traversal (in my implementation), conditional recursion, etc. One of the very few methods available for converting recursion into loops is trampolining. I've tried this and then found out that I need to implement eg. short-circuit boolean expression evaluation. In short, I've implemented a combination of a trampoline with continuations, and now I'm trying to find out whether this construction exists and what its name may be - as I've been unable to find any such already existing construct.
My implementation - bounce evaluation with manual stack handling:
function immediate($bounce, $args)
{
$stack = array($bounce->run($args));
while ($stack[0] instanceof Bounce) {
$current = array_pop($stack);
if ($current instanceof Bounce) {
$stack[] = $current;
$stack[] = $current->current();
} else {
$next = array_pop($stack);
$stack[] = $next->next($current);
}
}
return $stack[0];
}
The Bounce class:
class Bounce
{
protected $current;
protected $next;
public function __construct($current, $next)
{
$this->current = $current;
$this->next = $next;
}
public function current()
{
$fn = $this->current;
return $fn();
}
public function next($arg)
{
$fn = $this->next;
return $fn($arg);
}
}
And, as an example, short-circuit AND implementation (ie. in JavaScript first(args) && second(args)). $first and $second are functions that may return Bounces as well.
return new Bounce(
function () use ($first, $args) {
return $first($args);
},
function ($return) use ($second, $args) {
if (!$return) {
return $return;
}
return new Bounce(
function () use ($second, $args) {
return $second($args);
},
null
);
}
);
This allows for general recursion, with overhead of approximately 3 function calls per normal function call (though in the general case for variable iteration count, it is quite cumbersome to write and requires 'lazy recursion').
Has anyone seen such a structure before?
Im not so experienced in php , Im using codeigniter to write my application , I have my own library and within my library there are three functions/methods that passes there arguments in one function which is in one of my models , my question is how will i manipulate/trick the method in my model to know exactly which function among the three in my library has passed the value and return the correct value ..
1st function
public function id_exist ($id) {
if(empty($id)) {
return FALSE;
}
return $this->library_model->this_exist($id);
}
2nd function
public function group_exist($group) {
if(empty($group)){
return FALSE;
}
return $this->library_model->this_exist($group);
}
with the 3rd same as the above 2
in my model
public function this_exist ($item) {
if(empty($item) || !isset($item)) {
return FALSE;
}
// here is where i need to know which function has passed the argument so that i can work with it and return the correct value from the database
}
Might be dirty, might be not sophisticated, but why not passing another argument which tells exactly the origin?
public function id_exist ($id) {
if(empty($id)) {
return FALSE;
}
return $this->library_model->this_exist('id', $id);
}
public function group_exist($group) {
if(empty($group)){
return FALSE;
}
return $this->library_model->this_exist('group', $group);
}
Model:
public function this_exist ($origin, $item) {
if(empty($item) || !isset($item)) {
return FALSE;
}
if($origin == 'id'){
// do something
}
elseif($origin == 'group') {
// do something else
}
}
I have a validation class which uses method chaining. I would like to be able to do single checks with TRUE/FALSE like this:
if ($obj->checkSomething()) {}
But also chain methods like this:
if ($obj->checkSomething()->checkSomethingElse()) {}
The problem however is that if one method returns FALSE, it will not send back an object and thus breaks the method chaining which ends with this error:
Fatal error: Call to a member function checkSomething() on a non-object in ...
Do I have to pick either single method return calls or method chaining or is there a workaround?
One idea would be to set an internal flag to indicate success or failure, and access it via another method, while checking that flag in each method and not doing anything if it's set. E.g.:
class A {
private $valid = true;
public function check1() {
if (!$this->valid) {
return $this;
}
if (!/* do actual checking here */) {
$this->valid = false;
}
return $this;
}
public function check2() {
if (!$this->valid) {
return $this;
}
if (!/* do actual checking here */) {
$this->valid = false;
}
return $this;
}
public function isValid() {
return $this->valid;
}
}
// usage:
$a = new A();
if (!$a->check1()->check2()->isValid()) {
echo "error";
}
To minimize the boilerplate checking in each function, you could also use the magic method __call(). E.g.:
class A {
private $valid;
public function __call($name, $args) {
if ($this->valid) {
$this->valid = call_user_func_array("do" . $name, $args);
}
return $this;
}
private function docheck1() {
return /* do actual checking here, return true or false */;
}
private function docheck2() {
return /* do actual checking here, return true or false */;
}
public isValid() {
return $this->valid;
}
}
The usage would be same as above:
$a = new A();
if (!$a->check1()->check2()->isValid()) {
echo "error";
}
I believe you're looking to have an instance evaluate as true/false based on the outcome of validation.
While some languages allow you to override the boolean value of an instance, php does not (except for casting to string, that is. See PHP's Magic Methods).
Also, the booleans page in the PHP Manual has a list of things that evaluate to false, but it doesn't give any method of overriding the behavior either.
That being said, I'd suggest going with JRL's idea, and construct a chain of validation rules, then 'execute' it with a function that returns the boolean needed in your if statement.
You could wrap them up in a subclass, perhaps.
e.g. if you have
class Validate {
public function checkSomething($data) {
if ($data === $valid) {
return true;
}
return false;
}
public function checkSomethingElse($data) {
if ($data === $valid) {
return true;
}
return false;
}
}
You could do this:
class ValidateChain extends Validate {
protected $valid = true;
public function checkSomething($data) {
if (false === parent::checkSomething($data)) {
$this->valid = false;
}
return $this;
}
public function checkSomethingElse($data) {
if (false === parent::checkSomethingElse($data)) {
$this->valid = false;
}
return $this;
}
public function getIsValid() {
return $this->valid;
}
}
$v = new ValidationChain();
$valid = $v->checkSomething()->checkSomethingElse()->getIsValid();
Quick and dirty, E&OE. And you'd probably need to add a way to find out which bits weren't valid, etc.
Consider the following PHP snippet:
<?php
class Is
{
function __get($key)
{
$class = __CLASS__ . '_' . $key;
if (class_exists($class) === true)
{
return $this->$key = new $class();
}
return false;
}
function Domain($string)
{
if (preg_match('~^[0-9a-z\-]{1,63}\.[a-z]{2,6}$~i', $string) > 0)
{
return true;
}
return false;
}
}
class Is_Domain
{
function Available($domain)
{
if (gethostbynamel($domain) !== false)
{
return true;
}
return false;
}
}
$Is = new Is();
var_dump($Is->Domain('google.com')); // true
var_dump($Is->Domain->Available('google.com')); // false
?>
Is it possible to call the Available() method like this (and still return solely true or false if the Available method is not called)?
var_dump($Is->Domain('google.com')->Available()); // false
If yes, how?
EDIT: Would this do the trick?
class Is
{
function __get($key)
{
// same as before
}
function Domain($string)
{
if (preg_match('~^[0-9a-z\-]{1,63}\.[a-z]{2,6}$~i', $string) > 0)
{
return (bool) $this->Domain;
}
return false;
}
}
class Is_Domain
{
function __toString()
{
return true;
}
function Available($domain)
{
if (gethostbynamel($domain) !== false)
{
return true;
}
return false;
}
}
Thanks in Advance!
PS: This snippet is truncated, so don't expect it to make it a lot of sense just by its own.
Essentially you want a method to return either a bool or an object based on whether a subsequent method call to the result is going to occur. I don't think this will be possible without some massive hack (e.g. reading the PHP file in yourself and looking ahead), and it shouldn't be because your objects shouldn't be worrying about the context in which they are used.
Instead you could get the first call to return an object which is relevant in both cases, e.g. DomainLookupResult, which has two methods e.g. Exists() and IsAvailable(). You could then do:
$result = $Is->Domain('google.com');
$isValid = $result->Exists();
$isAvaliable = $result->IsAvailable();
//or chaining:
$isValid = $Is->Domain('google.com')->Exists();
$isAvailable = $Is->Domain('google.com')->IsAvailable();
You can only chain method calls if they return an object!
This is because you can only call methods on objects.
The problem with your code is that the methods return a non object value, either true or false. And the problem is not in any way solved better by chaining methods. You should use that where its applicable. Like chaining many setters, NOT getters which the methods you want to use essentially is.
var_dump($Is->Domain->Available('google.com')); // false
//is the same as
$res = $Is->Domain;
$res = $res->Available('google.com'));
var_dump($res);
So you see the first res is a boolean true or false, and you can not call a method on that.
edit
This might be a "solution". Not a good solution though since this is better without chaining.
class Domain
{
public $domain;
function setDomain($domain) {
$this->domain = $domain;
return $this;
}
function isDomain($domain = null) {
if (is_string($domain)) {
$this->setDomain($domain);
}
$result = gethostbynamel($this->domain) !== false;
return new Result($this, $result);
}
function isValid() {
$result = (bool) preg_match('', $this->domain);
return new Result($this, $result)
}
}
class Result
{
public $result;
public $object;
public function __construct($object, $result)
{
$this->result = $result;
$this->object = $object;
}
public function __call($method, $arguments)
{
if (is_object($this->result)) {
return call_user_func_array(array($this->result, $method), $arguments);
}
if (!$this->result) {
return $this;
}
return call_user_func_array(array($this->object, $method), $arguments);
}
}
$domain = new Domain();
var_dump($domain->isValid('google.com')->isAvailable()->result);
/edit
This will solve your problem above.
var_dump($Is->Domain('validandfreedomain.com') && $Is_Domain->Available('validandfreedomain.com')); // true
If you desperately want to chain a method for this problem you could make it more like this.
class Domain
{
public $domain;
function setDomain($domain) {
$this->domain = $domain;
return $this;
}
function isAvailable() {
return gethostbynamel($this->domain) !== false;
}
function isValid() {
return (bool) preg_match('', $this->domain);
}
}
$domain = new Domain();
$result = $domain->setDomain('validandfreedomain.com')->isValid() && $domain->isAvailable();
It is possible, if your function returns an object, you can call its method, and so on (see method chaining). The only limitation is - as far as a I know - is that you cannot chain calls from an object created by new ( new Object()->method1()->method2() ).
As for your example, I see no point in using either the dynamic class, or method chaining stuff.