PHP 8.3+ · English & Indonesian · zero dependencies
Sentiment analysis for PHP
Score English and Indonesian text as positive, negative or neutral. No API, no dependencies, no training. Just one composer require.
composer require risan/sentiment-analysisuse Risan\Sentiment\Sentiment;
$result = Sentiment::analyze('This package is awesome!');
$result->label; // Label::Positive$result->compound; // 0.6588$result->positive; // 0.594Built for real text
Section titled “Built for real text”Product reviews, support tickets, tweets, comments. The kind of text people actually write, with typos, shouting and emoji.
English and Indonesian
One API, two languages. English runs the VADER rules; Indonesian has its own lexicon and rules for negation, intensifiers and informal spelling.
Reads like a person
Understands "not good", "very good", "GOOD!!!", "good, but…", emoticons and emoji, not just a bag of words.
Zero dependencies
Pure PHP 8.3+ with ext-mbstring. No API keys, no network calls, no model files, nothing to train.
Fast and light
About 80,000 short texts per second. Lexicons are plain PHP arrays that OPcache keeps in shared memory.
Yours to tune
Add or override words, drop words, move the neutral threshold. Every analyzer is immutable, so one tweak never leaks into another.
MIT licensed
Built on the published VADER algorithm, checked against the reference implementation. The Indonesian lexicon is written for this project.
See how it scores
Section titled “See how it scores”Every analysis returns a label and four numbers: a compound score from -1 (most negative) to +1 (most positive), plus the share of positive, neutral and negative signal in the text.
| Text | Label | Compound | Pos | Neu | Neg |
|---|---|---|---|---|---|
| This package is awesome!English | positive | 0.6588 | 0.594 | 0.406 | 0.000 |
| The movie was good.English | positive | 0.4404 | 0.492 | 0.508 | 0.000 |
| The movie was not good.English | negative | -0.3412 | 0.000 | 0.624 | 0.376 |
| It isn't bad at all.English | positive | 0.4310 | 0.416 | 0.584 | 0.000 |
| The service was extremely good.English | positive | 0.4927 | 0.444 | 0.556 | 0.000 |
| The service was kind of good.English | positive | 0.3832 | 0.343 | 0.657 | 0.000 |
| The plot was good, but the ending was terrible.English | negative | -0.4939 | 0.149 | 0.534 | 0.317 |
| I LOVE this phone.English | positive | 0.7125 | 0.622 | 0.378 | 0.000 |
| The concert was great!!!English | positive | 0.7163 | 0.624 | 0.376 | 0.000 |
| Thanks for the help :)English | positive | 0.8225 | 0.811 | 0.189 | 0.000 |
| Loved the show 😍English | positive | 0.7845 | 0.580 | 0.420 | 0.000 |
| Worst day ever 😭English | negative | -0.8020 | 0.000 | 0.357 | 0.643 |
| The meeting is at 3 pm.English | neutral | 0.0000 | 0.000 | 1.000 | 0.000 |
| Filmnya bagus banget!Indonesian | positive | 0.6230 | 0.671 | 0.329 | 0.000 |
| Makanannya enak sekali.Indonesian | positive | 0.5849 | 0.655 | 0.345 | 0.000 |
| Pelayanannya tidak ramah.Indonesian | negative | -0.3570 | 0.000 | 0.446 | 0.554 |
| Tempatnya nyaman tapi harganya mahal.Indonesian | negative | -0.1280 | 0.267 | 0.400 | 0.333 |
| Aku BENCI antrean panjang!!!Indonesian | negative | -0.6817 | 0.000 | 0.394 | 0.606 |
| Hotelnya lumayan, tapi kamarnya kotor.Indonesian | negative | -0.6428 | 0.162 | 0.324 | 0.514 |
| Kamera hp ini keren parah 😍Indonesian | positive | 0.7778 | 0.492 | 0.508 | 0.000 |
| Besok rapat jam 3 sore.Indonesian | neutral | 0.0000 | 0.000 | 1.000 | 0.000 |
One API, two languages
Section titled “One API, two languages”use Risan\Sentiment\Sentiment;
$result = Sentiment::analyze('Not bad at all!');
$result->isPositive(); // trueuse Risan\Sentiment\Language;use Risan\Sentiment\Sentiment;
$result = Sentiment::analyze( 'Filmnya bagus banget!', Language::Indonesian,);
$result->isPositive(); // trueReady to try it?
Section titled “Ready to try it?”Install the package and score your first sentence in under a minute.