'Dynamically generate PHP static methods to instantiate new object

I am trying to build a database-class that allows method chaining to query it. I want to instantiate it like Laravel's Eloquent by making the first call static.

See this example:

class Database
{
    public function construct($data) {
        $this->data = $data;
    }
    public function filter($criteria) {
        // ...
        return $this;
    }
    public static function filter($data, $criteria) {
        $obj = new Database($data);
        $obj->filter($criteria);
        return $obj;
    }
    public function add($value) {
        // ...
        return $this;
    }
    public static function add($data, $value,) {
        $obj = new Database($data);
        $obj->add($value);
        return $obj;
    }
}

This would allow me for example:

Database::add($myData, $newValue)->add($anotherValue)->filter('isString');
Database::filter($myData, 'isNumber')->add($thirdValue);

This is not supposed to be the real thing, but I am curious if there was a way to reduce the duplicated code throughout my static methods or to remove them entirely. I thought of the magic method __callStatic() but I am not sure if it is the best way to achieve it.

I would appreciate it if someone who knows could explain me, how big frameworks deal with this kind of task.



Solution 1:[1]

You can use static methods from object, but you cannot use $this in that method.

You cannot define static and not static methods with the same name.

In most cases I need only the not static method, and in rare case I don't have an object instance I instantiate just for this method call - and call the non-static method.

In rare cases I define the static method too with different name, for example filterStatic(). This is a very rare case, and in this case the non-static method wraps the static one to avoid code duplication.

Solution 2:[2]

My answer is assuming you're using . for digit separator and , for the decimal point.

m = fila['Operado'].strip()    # m = "22.024.833,02"
m = m.replace('.', '')         # m = "22024833,02"
m = m.replace(',', '.')        # m = "22024833.02"
monto = float(m)               # monto = 22024833.02

Python's float expects no digit separator (the . in your example), and the decimal point to be a . (not a , as in your input).

Solution 3:[3]

I think this is what you are looking for

m = float(fila['Operado'].strip().replace(".","").replace(",","."))

Its better to use . for decimal places and , for the whole number part.

Solution 4:[4]

In Python you should use . instead of , as decimal separator.

good_float = 1.44
not_a_float = 1,22 # This will be stored as a tuple

If your input string is written with , as decimal separator, you can use String.replace() method.

>>> '3,14'.replace(',', '.')
'3.14'

If you are also using . as digit separator, you can replace it with the same method.

>>> '1.203,14'.replace('.', ' ').replace(',', '.')
'1203,14'

Then you can finely convert the string to a float using the float built-in function.

>>> float('3,14'.replace('.', ' ').replace(',', '.'))
3.14

Remember to always write .replace('.', ' ') before .replace(',', '.') to avoid a mess with periods.


Your code should work now:

>>> float(fila['Operado'].strip().replace('.', ' ').replace(',', '.'))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 DBLaci
Solution 2
Solution 3 Rachit Kawar
Solution 4