zephir-lang / zephir

Zephir is a compiled high-level language aimed to ease the creation of C-extensions for PHP
https://zephir-lang.com
MIT License
3.3k stars 466 forks source link

About variables initialized #1875

Open dreamsxin opened 5 years ago

dreamsxin commented 5 years ago

See https://github.com/phalcon/cphalcon/pull/14193 @sergeyklay @niden

$validation = new Phalcon\Validation();

$validation->bind(
    new stdClass(),
    [
        'day'   => date('d'),
    ]
);
$_POST = ['day' => 'test'];
 $validator = new Phalcon\Validation\Validator\StringLength(
    [
        'min'            => 3,
        'max'            => 20,
    ]
);

var_dump($validator->validate($validation, 'day'), $validation->getMessages());

Will happen Variable 0x7ffd95e52240 is already observed#0 Zephir code:

 class StringLength extends ValidatorComposite
{
    public function __construct(array! options = []) -> void
    {
        var included, key, message, validator, value;
        for key, value in options {
            if strtolower(key) === "min" {
               // ...
                if isset options["included"] {
                    let included = options["included"];
                } elseif isset options["includedMinimum"] {
                    let included = options["includedMinimum"];
                }
                // Should add let included = null;

                let validator = new Min(
                    [
                        "min" : value,
                        "message" : message,
                        "included" : included
                    ]
                );
               // ...
            }
            // ...
        }
    }
}

class Min extends Validator
{
    public function validate(<Validation> validation, var field) -> bool
    {
        let included = this->getOption("included"); // zephir_memory_observe #0, included == undef

        if typeof included == "array" {
            let included = (bool) included[field];
        } else {
            let included = (bool) included; // zephir_memory_observe
        }
        // ...
        return true;
    }
}
niden commented 5 years ago

Yes I saw that earlier on these https://travis-ci.org/phalcon/cphalcon/jobs/548411093#L1439

Something we can fix in Phalcon or is this Zephir based?

dreamsxin commented 5 years ago

@niden Fix in Phalcon

if isset options["included"] {
    let included = options["included"];
} elseif isset options["includedMinimum"] {
    let included = options["includedMinimum"];
} else {
   let included = null;
}

or

var included = null;

If fix in zephir, all variables are initialized by default to NULL, or judge initialization when you use it, but it's more cumbersome.

sergeyklay commented 4 years ago

@dreamsxin I think we should go in that direction: Any scalar type should have its own "default constructor" like in other languages (C++, Golang). In that scenario variables declared without an initial value are set to their zero values:

Even more, I would like expect such behavior:

int n;
double d;
var v;

array t = [ n, d, v ];

var_dump(t);
array(3) {
  [0]=>
  int(0)
  [1]=>
  float(0)
  [2]=>
  NULL
}

Refs: https://github.com/phalcon/zephir/issues/1835

dreamsxin commented 4 years ago

@sergeyklay Then we have to modify the memory management, judged by the judgment type undef.

#define ZEPHIR_INIT_NVAR(z) \
    do { \
        if (Z_TYPE_P(z) == IS_UNDEF) { \
            zephir_memory_observe(z); \
        } else if (Z_REFCOUNTED_P(z) && !Z_ISREF_P(z)) { \
            if (Z_REFCOUNT_P(z) > 1) { \
                Z_DELREF_P(z); \
            } else { \
                zval_dtor(z); \
            } \
        } \
        ZVAL_NULL(z); \
    } while (0)