Master backend architectures, REST API design, microservices, and server-side development across multiple languages. Use this as a central index to access specialized sub-skills.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Analyzes PHP code for encapsulation violations. Detects public mutable state, exposed internals, Tell Don't Ask violations, getter/setter abuse, and information hiding breaches.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
This skill analyzes PHP codebases for encapsulation violations — situations where internal state is exposed, getters/setters replace behavior, or the "Tell, Don't Ask" principle is violated.
| Principle | Description | Violation Indicator |
|---|---|---|
| Information Hiding | Internal state not exposed | Public properties, many getters |
| Tell Don't Ask | Objects perform actions, not expose data | Getter chains, external decisions |
| Behavioral Richness | Objects have behavior, not just data | Anemic domain model |
| Invariant Protection | State changes validate constraints | Public setters without validation |
# Public properties (non-readonly)
Grep: "public string|public int|public float|public bool|public array|public \?" --glob "**/Domain/**/*.php"
# Public properties in entities
Grep: "public \$|public string \$|public int \$" --glob "**/Entity/**/*.php"
# Expected: private/protected or public readonly
Grep: "public readonly|private readonly|protected readonly" --glob "**/Domain/**/*.php"
Violations:
// BAD: Public mutable state
class User
{
public string $email; // Can be modified externally!
public int $age; // No validation!
public array $permissions; // Collection exposed!
}
// GOOD: Encapsulated state
final class User
{
private Email $email;
private Age $age;
private PermissionCollection $permissions;
public function changeEmail(Email $newEmail): void { /* ... */ }
public function grantPermission(Permission $permission): void { /* ... */ }
}
# Getter/setter pairs (anemic model indicator)
Grep: "public function get[A-Z][a-z]+\(\)" --glob "**/Domain/**/*.php"
Grep: "public function set[A-Z][a-z]+\(" --glob "**/Domain/**/*.php"
# Count getters vs behavior methods
# High getter ratio = anemic model
# Setters in entities (should be behavior methods)
Grep: "public function set[A-Z]" --glob "**/Entity/**/*.php"
Grep: "public function set[A-Z]" --glob "**/Aggregate/**/*.php"
# Direct property setters
Grep: "\$this->[a-z]+ = \$" --glob "**/Domain/**/*.php"
# Check if inside validated method or public setter
Getter/Setter Anti-pattern:
// BAD: Anemic entity
class Order
{
public function getStatus(): string { return $this->status; }
public function setStatus(string $status): void { $this->status = $status; }
}
// External code makes decisions
if ($order->getStatus() === 'pending') {
$order->setStatus('confirmed');
}
// GOOD: Rich entity
final class Order
{
public function confirm(): void
{
if ($this->status !== OrderStatus::PENDING) {
throw new CannotConfirmOrderException();
}
$this->status = OrderStatus::CONFIRMED;
$this->recordEvent(new OrderConfirmedEvent($this->id));
}
}
# Getter chains (asking for data to make decisions)
Grep: "->get[A-Z][a-z]+\(\)->get[A-Z][a-z]+\(\)" --glob "**/*.php"
Grep: "if \(\$.*->get[A-Z].*->get[A-Z]" --glob "**/*.php"
# External conditionals on object state
Grep: "if \(\$[a-z]+->get[A-Z][a-z]+\(\) ===" --glob "**/*.php"
Grep: "if \(\$[a-z]+->is[A-Z][a-z]+\(\))" --glob "**/*.php"
# Switch on object state
Grep: "switch \(\$.*->get[A-Z]|match \(\$.*->get[A-Z]" --glob "**/*.php"
Tell Don't Ask Pattern:
// BAD: Ask then act
if ($user->getBalance()->getAmount() >= $payment->getAmount()) {
$user->setBalance(
$user->getBalance()->subtract($payment->getAmount())
);
}
// GOOD: Tell
$user->pay($payment);
// Inside User
public function pay(Payment $payment): void
{
if (!$this->balance->canAfford($payment->amount())) {
throw new InsufficientBalanceException();
}
$this->balance = $this->balance->subtract($payment->amount());
$this->recordEvent(new PaymentMadeEvent($this->id, $payment->id()));
}
# Returning mutable collections
Grep: "public function get[A-Z][a-z]+\(\): array" --glob "**/Entity/**/*.php" -A 3
# Check if returns internal array directly
# Doctrine collections exposed
Grep: "public function get[A-Z][a-z]+\(\): Collection" --glob "**/Domain/**/*.php"
# Array modifications outside entity
Grep: "\$.*->get[A-Z][a-z]+\(\)\[\]|array_push\(\$.*->get" --glob "**/*.php"
Collection Encapsulation:
// BAD: Collection exposed
class Order
{
/** @return OrderItem[] */
public function getItems(): array
{
return $this->items; // Internal array exposed!
}
}
// External modification
$order->getItems()[] = $newItem; // Bypasses validation!
// GOOD: Collection encapsulated
final class Order
{
public function addItem(Product $product, Quantity $quantity): void
{
$this->validateCanAddItem($product);
$this->items[] = new OrderItem($product, $quantity);
$this->recalculateTotal();
}
/** @return OrderItem[] */
public function items(): array
{
return [...$this->items]; // Return copy
}
}
# Internal state returned
Grep: "return \$this->[a-z]+;" --glob "**/Domain/**/*.php"
# Check if returning mutable objects
# Private field via reflection
Grep: "ReflectionClass|ReflectionProperty|setAccessible" --glob "**/*.php"
# Debug/dump methods exposing state
Grep: "public function toArray\(\)|public function dump\(\)|public function debug\(\)" --glob "**/Domain/**/*.php"
# Serialization exposing internals
Grep: "__serialize|__sleep|jsonSerialize" --glob "**/Domain/**/*.php"
# Too many dependencies (SRP violation indicator)
Grep: "__construct\(" --glob "**/Domain/**/*.php" -A 15
# Count parameters
# Public constructor with complex setup
Grep: "public function __construct" --glob "**/Domain/**/*.php" -A 20
# Check for business logic in constructor
# Missing factory for complex construction
Grep: "new [A-Z][a-z]+Entity\(|new [A-Z][a-z]+Aggregate\(" --glob "**/Application/**/*.php"
# Complex instantiation outside factory
# Encapsulation Analysis Report
## Summary
| Issue Type | Critical | Warning | Info |
|------------|----------|---------|------|
| Public Mutable State | 3 | 5 | - |
| Getter/Setter Abuse | 2 | 8 | 12 |
| Tell Don't Ask | 4 | 15 | - |
| Collection Exposure | 2 | 6 | - |
| Exposed Internals | 1 | 3 | 4 |
**Encapsulation Score: 68%**
## Critical Issues
### ENC-001: Public Mutable Properties
- **File:** `src/Domain/User/Entity/User.php:12`
- **Issue:** Public properties allow external modification
- **Code:**
```php
public string $email;
public string $name;
public array $roles;
private Email $email;
private Name $name;
private RoleCollection $roles;
public function changeEmail(Email $email): void { /* validate */ }
acc-create-entity, acc-create-value-objectsrc/Domain/Order/Entity/Order.phppublic function getStatus(): string { ... }
public function setStatus(string $status): void { ... }
public function confirm(): void { /* validate and transition */ }
public function ship(TrackingNumber $tracking): void { /* ... */ }
public function cancel(CancellationReason $reason): void { /* ... */ }
acc-create-entitysrc/Application/Service/OrderService.php:45$order->getItems()[] = $newItem;
$order->addItem($product, $quantity);
src/Application/Handler/ConfirmOrderHandler.php:34if ($order->getStatus() === 'pending' &&
$order->getPayment()->getStatus() === 'completed') {
$order->setStatus('confirmed');
}
$order->confirm(); // Validation inside entity
src/Application/Service/ReportService.php:78$country = $user->getAddress()->getCity()->getCountry()->getName();
$user->countryName()new Report($user->address()->countryName())src/Domain/Order/Entity/Order.php:89public function getItems(): array
{
return $this->items;
}
/** @return OrderItem[] */
public function items(): array
{
return [...$this->items]; // Return copy
}
| Entity | Getters | Setters | Behavior | Ratio | Status |
|---|---|---|---|---|---|
| User | 8 | 5 | 3 | 4.3 | ⚠️ Poor |
| Order | 15 | 12 | 2 | 13.5 | ❌ Anemic |
| Product | 6 | 0 | 5 | 1.2 | ✅ Good |
| Payment | 4 | 2 | 4 | 1.5 | ✅ Good |
Target: Ratio < 2.0 (behaviors should outnumber getters)
| Layer | Public Props | Readonly Props | Private Props |
|---|---|---|---|
| Domain | 12 ❌ | 8 | 45 |
| Application | 0 | 23 | 15 |
## Encapsulation Patterns
### Rich Entity Example
```php
final class Order
{
private OrderId $id;
private CustomerId $customerId;
private OrderStatus $status;
private OrderItemCollection $items;
private Money $total;
private array $events = [];
public static function create(CustomerId $customerId): self
{
$order = new self();
$order->id = OrderId::generate();
$order->customerId = $customerId;
$order->status = OrderStatus::DRAFT;
$order->items = new OrderItemCollection();
$order->total = Money::zero();
$order->recordEvent(new OrderCreatedEvent($order->id));
return $order;
}
public function addItem(Product $product, Quantity $quantity): void
{
$this->assertDraft();
$item = OrderItem::create($product, $quantity);
$this->items = $this->items->add($item);
$this->recalculateTotal();
}
public function submit(): void
{
$this->assertDraft();
$this->assertHasItems();
$this->status = OrderStatus::SUBMITTED;
$this->recordEvent(new OrderSubmittedEvent($this->id));
}
// Query methods (no state exposure)
public function id(): OrderId { return $this->id; }
public function total(): Money { return $this->total; }
public function isSubmitted(): bool { return $this->status->equals(OrderStatus::SUBMITTED); }
private function assertDraft(): void
{
if (!$this->status->equals(OrderStatus::DRAFT)) {
throw new OrderNotDraftException($this->id);
}
}
}
# Check encapsulation
echo "=== Public Properties ===" && \
grep -rn "public string\|public int\|public array" --include="*.php" src/Domain/ | grep -v "readonly" && \
echo "=== Setter Methods ===" && \
grep -rn "public function set[A-Z]" --include="*.php" src/Domain/ && \
echo "=== Getter Chains ===" && \
grep -rn "->get[A-Z].*->get[A-Z].*->get[A-Z]" --include="*.php" src/ && \
echo "=== Tell Don't Ask ===" && \
grep -rn "if (\$.*->get[A-Z].*===\|switch (\$.*->get[A-Z]" --include="*.php" src/Application/
Works with:
acc-detect-code-smells — Feature Envy, Anemic Modelacc-structural-auditor — DDD complianceacc-create-entity — Generate rich entitiesacc-create-value-object — Encapsulated value types아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Master backend architectures, REST API design, microservices, and server-side development across multiple languages. Use this as a central index to access specialized sub-skills.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
在每次回复中使用固定前缀并列出本次实际参考的指令/文件,便于校验是否遵循上下文与规则。
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Automate 21risk tasks via Rube MCP (Composio). Always search tools first for current schemas.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Automate 2chat tasks via Rube MCP (Composio). Always search tools first for current schemas.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Arquitecto de Soluciones Principal y Consultor Tecnológico de Andru.ia. Diagnostica y traza la hoja de ruta óptima para proyectos de IA en español.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
[00] META. Orchestrate skills into dynamic chains for complex tasks. Analyzes the task, discovers available skills, builds an optimal chain, explains why each skill is needed, and executes step-by-step with user confirmation. Use for any complex task requiring multiple thinking/research/analysis steps. Triggers on "plan this", "how to approach", "what's the strategy", "build a plan", or any multi-step problem requiring skill orchestration.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.