Skip to content

Arithmetic magic methods #3735

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Conversation

henrique-borba
Copy link

@henrique-borba henrique-borba commented Jan 7, 2019

I'm currently developing an extension for PHP for matrix calculations but PHP does not have the option of intercepting arithmetic operations using objects. I then decided to update the arithmetic functions in zend_operators.c to work with objects.

Use Case

<?php
class MyArithmeticClass {
    public $value;

    public function __construct($value)
    {
          $this->value = $value;
    }

    public function __add($obj) {
        return new MyArithmeticClass($this->value + $obj->value);
    }
    public function __mul($obj) {
        return new MyArithmeticClass($this->value * $obj->value);
    }
    public function __div($obj) {
        if(is_object($obj)) {
            return new MyArithmeticClass($this->value / $obj->value);
        }
        if(is_long($obj)) {
            return new MyArithmeticClass($this->value / $obj);    
        }
    }
    public function __sub($obj) {
        return new MyArithmeticClass($this->value - $obj->value);
    }
}

$a = new MyArithmeticClass(1);
$b = new MyArithmeticClass(2);

$c = $a * $b * $b / 2;

print_r($c);
MyArithmeticClass Object
(
    [value] => 2
)

These feature is especially relevant for Math and Linear Algebra libraries. Currently, if I want to create a library to multiply and add arrays, it would have to be developed in a way that calls become repetitive and often make a mess:

$a = new CustomArray([1, 2]);
$b = new CustomArray([3, 4]);
$c = $a->add($b)->add(2)->dot($a)->sub($b);

This could be written like:

$a = new CustomArray([1, 2]);
$b = new CustomArray([3, 4]);
$c = $a + ($b + 2) * $a - $b;

Some people however could use these methods to add an object to a collection in a different (maybe bizarre) way:

$people = new People();

$people->add($person);
//  could be written
$people = $people + $person;
// or maybe removing a person from the people collection
$people = $people - $person;

PS: Only an example, I personally would stay with $people::add in this case.

@henrique-borba
Copy link
Author

henrique-borba commented Jan 7, 2019

Currently the summation operation with arrays works like concatenation and this is causing the errors. I will fix it.

@nikic
Copy link
Member

nikic commented Jan 7, 2019

I'm currently developing an extension for PHP for matrix calculations but PHP does not have the option of intercepting arithmetic operations using objects. I then decided to update the arithmetic functions in zend_operators.c to work with objects.

PHP does support this via the do_operation object handler.

@henrique-borba
Copy link
Author

henrique-borba commented Jan 7, 2019

@nikic Thanks a lot! You just solved a nightmare for me, this was essential to my project. I didn't realize the existence of this object handler.

Not wanting to take up too much of your time, but then the implementation would be something like:

static zend_object_handlers my_handler;

ZEND_MINIT_FUNCTION(MyProject)
{
        memcpy(&myproject_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
        myproject_object_handlers.do_operation = my_do_operation;
}

Is this correct?

Thanks again

@nikic
Copy link
Member

nikic commented Jan 7, 2019

@henrique-borba Right, and you will also have to assign your custom object handlers inside your create_object class handler (or create it if you don't have one yet).

You can take a look at ext/gmp for an example of an extension that uses do_operation.

@weltling
Copy link
Contributor

weltling commented Jan 7, 2019

@nikic does do_operation respect the operands order? I remember some discrepancy, or it was an Opcache optimization, so operands for * were swapped. Just asking as the operands order is critical for the matrix math.

Thanks.

@nikic
Copy link
Member

nikic commented Jan 7, 2019

@weltling I think there are some opcache optimizations that may swap operand order. We can drop them for ZEND_MUL at least.

@nikic
Copy link
Member

nikic commented Jan 8, 2019

I've removed the opcache optimization that I'm aware of in 1165a90. Maybe there are others.

@nikic
Copy link
Member

nikic commented Jan 9, 2019

As we already have the do_operation mechanism, I'm going to close this PR. Feel free to ping me if you encounter any problems with it.

@nikic nikic closed this Jan 9, 2019
@henrique-borba
Copy link
Author

Hi @nikic,

Thanks a lot again. I'm happy to see you cared about OPCache swaps. I just realized I must opened an RFC por this kind of change, anyway, I don't think I will do it as your guidance was enough. I realize your OPCache change would only affect PHP next major release (Am I wrong?). Is it possible to detect operand swap before it happens? I would like to make arithmetic operations available for PHP 7.X. I could for example, swap the operands before OPCache swap so theier order will be as expected?

Excuse my english, I refuse using Google Translator haha.

Anyway, thanks a lot. @nikic I'm a big fan of your work, just having your attention is a win. See you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants