We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Help with Static Function Use in Zephir

Having a little issue with Zephir. Maybe someone can shed some light on it here since there isn't a Zephir forum to post to???

I have an extension named classes. In my classes/classes/ directory I have two files: config.zep and database.zep. When I try to build my extension, it seems to stop on an odd issue I can't explain. For some background heres my config.zep file.

namespace Classes;

class Config {
    protected static config = [];

    public static function get(name, default_var = null) {
        return isset(self::config[name]) ? self::config[name] : default_var;
    }

    public static function has(name) {
        return array_key_exists(name, self::config);
    }

    public static function set(string name, value) {
        let self::config[name] = value;
    }

    public static function add(parameters = []) {
        let self::config = array_merge(self::config, parameters);
    }

    public static function getAll() {
        return self::config;
    }

    public static function clear() {
        let self::config = [];
    }
}

In my database.zep file here's the start of the class (it's been gutted obviously) and it keeps have problems on my first function, the line with var db_ip

namespace Classes;

class Database {
    public database;

    public function connect(string override_db = '') -> void {
        var db_ip = Config::get('db_ip');
        var dbs = Config::get('dbs');
    }
}

This is the error I get when trying to build my extension.

Zephir\ParseException: Syntax error in /root/zephir_proj/classes/classes/database.zep on line 20

      var db_ip = Config::get('db_ip');
    ------------------------^

Any thoughts? I've try Classes\Config and it doesn't like that. I've tried including use Classes\Config as Config; under the name space line and it blows up as well. I've tried many variations with no success on why I can't call Config::get(); I've even tried renameing that class to Setting and Settinger with no success. It keeps breaking in the same spot.



98.9k
Accepted
answer
edited Mar '14

'var' only must be used to declare variables:

 public function connect(string override_db = "") -> void
 {
        var db_ip, dbs;     
        let db_ip = Config::get("db_ip"),
            dbs = Config::get("dbs");
}

Also, single quotes are used for chars (https://en.wikipedia.org/wiki/Character_(computing) and double quotes for strings https://en.wikipedia.org/wiki/String_(computer_science)



2.8k
edited Mar '14

@Phalcon That was it. Still getting used to the syntax, but it makes sense now that you mentioned that stuff. I kept thinking that it had something to do with my Config class. This is my first adventure away from php land.

Two other things now that you bring it up. In how I've learned php, I generally keep everything single quotes (strings included) because from what I understand that with double quotes, php has to look within the string to see if there are variables it needs to parse. While on a small scale, that performance gain is microscopic, on a larger scale, I've understand that it at least helps a tad.

With Zephir though, is the goal with single vs. double quotes a separation of concern? Does Zephir define chars in the sense of something that is like.....a word or something similar to what you'd name a variable (a "single" word without spaces) or a key in an array, and a string would be something more of what you'd put in a sentence (email message, SQL, etc)?

Also, for optimization purposes within Zephir, is there a performance difference between defining the vars and then using let to change them like you did in the example, or is it the same performance wise, if I just did used let, and never defined the var in the beginning?



98.9k

Single quotes are used to represent 8-bit characters: 'A', 'b', 'c', ' ', '0', '\0', '\n', etc

In PHP, C or Zephir, strings are sequences of characters that are implicitly null terminated. This means that "hello" is in fact, 'h', 'e', 'l', 'l', 'o', '\0',

However, in PHP, when you manipulate a string char-by-char, you're creating an implicit string to store every character requiring additional memory:


$text = "hello";
$length = strlen($text);
for ($i = 0; $i < $length; $i++) {
   $ch = substr($text, $i, 1); // allocate a zval (48 bytes) + string (1 byte) + null termination (1 byte) = 34 bytes
   echo $ch;
}

In Zephir, the 'char' type does exist, it can access a character without having to allocate memory for it:

let text = "hello";
for ch in text {
    echo ch; // this makes a Z_STRVAL_P(text) + i 
}

echo text[ch]; 

Depending on the scenario and the size of the strings being handled, it could be a significant reduction in memory.



2.8k
edited Mar '14

@Phalcon thanks for your help with me understanding that. Makes perfect sense.

So I've continued to build this and it looks like there are some possible issues to look at? From what I gathered, for now at least it looks like Zephir first makes a pass and checks syntax, and then it makes another pass and checks for rules (if a function really returns a boolean like I asked it to, etc).

I was going through just fixing each error that would come up, and then all of a sudden it just stopped working altogether and threw an error when I tried to build my project. I still have over half of my script to go through and I'm sure it has plenty of other errors to check. Here is the error below:

PHP Warning:  require(/root/zephir/Library/Operators/Unary/CompilerException.php): failed to open stream: No such file or directory in /root/zephir/Library/Loader.php on line 48
PHP Fatal error:  require(): Failed opening required '/root/zephir/Library/Operators/Unary/CompilerException.php' (include_path='.:/usr/share/pear:/usr/share/php') in /root/zephir/Library/Loader.php on line 48

I even just barely pulled from the repo a few minutes ago just to update my code and it still didn't work. Is there something I'm missing? I had problems when I was using PHP 5.3, But when I upgraded PHP 5.4 errors I was experiencing went away. I'm using PHP 5.4.25 and it looks like Zephir is version 0.4.0a.



2.8k
edited Mar '14

Aha, I think I narrowed it down. I just kept commenting out functions until I found it.

It looks like Zephir hates me when I try to just !sql in an if statement.

public function getSql(string sql = "") -> string|boolean {
        var statement, sql;

        // it hates this apparently     
        if(!sql) {
            let sql = this->sql;
        }

        // more code
}

I don't know if this is a bug in the code or if this is an error, but I just thought I'd let you know.



98.9k

Could you please post the "hate" message Zephir is producing?



2.8k
edited Mar '14
Could you please post the "hate" message Zephir is producing?

@Phalcon That php warning/fatal error is the hate message I was getting. If you read up a post, I fixed what was causing it. What fixed it was changing !sql to sql == ""



2.8k

Just in case you didn't get my notification @Phalcon cause I edited it



98.9k

Could you please create a issue on the Zephir repo? https://github.com/phalcon/zephir