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).Seriesdoes not implementCountable; uselen().__toString()gives Polars’ table layout, soecho $dfprints likeprint(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"); usecol('b')for a column. SeriesandDataFramemethods 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.