phpolars

Guides

Coming from py-polars

phpolars keeps py-polars’ names and semantics, and most differences come from PHP’s syntax. The test suite checks 314 operations against py-polars 1.43.2; Compatibility and limitations describes what those cases cover.

Naming

py-polars phpolars
pl.col("x") col('x')
pl.lit(1) lit(1)
pl.when(c).then(a).otherwise(b) when($c)->then($a)->otherwise($b)
df.with_columns(...) $df->withColumns(...)
df.group_by("g").agg(...) $df->groupBy('g')->agg(...)
df.to_dicts() $df->toDicts()
pl.read_csv(path) read_csv($path)
df.join(o, left_on="a", right_on="b") $df->join($o, leftOn: 'a', rightOn: 'b')
pl.col("s").str.contains("x") col('s')->str()->contains('x')
pl.col("t").dt.year() col('t')->dt()->year()
expr.mod(2), expr % 2 $expr->mod(2)
a + b, a > b $a->add($b), $a->gt($b)
pl.Int64 'Int64' or DataType::Int64
import polars.selectors as cs, cs.numeric() use Phpolars\cs;, cs\numeric()
cs.numeric() - cs.by_name("id") cs\numeric()->sub(cs\by_name('id'))
for key, group in df.group_by("g") foreach ($df->groupBy('g') as $key => $group)
df.sql("SELECT ..."), pl.SQLContext $df->sql('SELECT ...'), new SQLContext([...])

Methods are camelCase. Functions are snake_case in the Phpolars namespace. Named parameters are camelCase. PHP has no operator overloading, so arithmetic and comparison are methods: add, sub, mul, truediv, floordiv, mod, pow, eq, ne, gt, ge, lt, le, and, or, not.

Variadic arguments and **named

Where py-polars takes *exprs, the method is variadic. An associative array stands in for **named_exprs:

$df->select('a', col('b')->mul(2), ['c' => col('x')->sum()]);
$df->groupBy('g')->agg(col('x')->mean(), ['n' => len()]);

PHP does not allow parameters after a variadic one. Methods that need both take a single argument that accepts a name, an Expr, or a list:

$df->groupBy(['store', 'product'], maintainOrder: true);
col('x')->sum()->over(['g', 'h'], orderBy: 'day');
$df->drop('a', 'b');

Values

Results come back as PHP values: int, float, bool, string, null, DateTimeImmutable for dates and datetimes, lists for List columns, and associative arrays for Struct columns. See Types and values.

Names PHP reserves

PHP keywords cannot be function names, so a few functions take a trailing underscore, as struct_() does: var_(), and the selectors cs\list_(), cs\array_(), cs\empty_(), and cs\enum_(). Methods keep their py names, because PHP allows keywords there: $expr->struct(), $expr->list().

Python callables

py-polars methods that run a Python function per value or per batch, such as map_elements, map_batches, fold, and map_groups, have no phpolars equivalent. Polars runs expressions on its own threads, and PHP code cannot run there. Use expressions instead. DataFrame::mapRows() is the exception: it runs on the PHP thread, after collecting, and calls a PHP callable per row.

Small differences

  • Series::count() keeps py’s meaning (non-null values). Series does not implement Countable; use len().
  • __toString() gives Polars’ table layout, so echo $df prints like print(df).
  • DataFrame::toColumns() is a phpolars addition: toDict(asSeries: false).
  • Strings in arithmetic are literals in phpolars, as they are in comparisons. py treats a string as a column name in some operators (col("a") - "b") but not others (col("a") + "b"); use col('b') for a column.
  • Series and DataFrame methods never change the object in place. py’s in-place methods (scatter, set, extend, insert_column, replace_column) return a new object.
  • read_database() takes a PDO connection.

From phpstats/phpolars@8487062.