# Языки и базовые соглашения

Версия источника: d33454c0dad753475ecc92aaecf8d783f02fd01b
Синхронизировано: 2026-11-13T05:38:20.984Z
Источник: https://github.com/sergey-from-riders/vibecoding-base/tree/d33454c0dad753475ecc92aaecf8d783f02fd01b

## Оглавление

- [Go: имена, экспорт и инициализмы](#languages-go-naming)
- [Go: явные imports и границы пакета](#languages-go-imports)
- [Go: типы и проверка значений на границе](#languages-go-types)
- [Go: версия toolchain и граф модулей](#languages-go-toolchain)
- [Python: имена классов, функций и констант](#languages-python-naming)
- [Python: явные imports и управляемая инициализация](#languages-python-imports)
- [Python: аннотации и runtime-валидация](#languages-python-types)
- [Python: интерпретатор, окружение и зависимости](#languages-python-toolchain)
- [Имена в JavaScript и TypeScript](#languages-javascript-naming)
- [Привязки const и let](#languages-bindings)
- [Проверка внешних данных в TypeScript](#languages-runtime-boundaries)
- [Отсутствие, null и undefined](#languages-nullability)
- [Результаты и ошибки Promise](#languages-promise-errors)
- [Модули и разрешение импортов](#languages-module-boundaries)
- [PHP: типы и проверка входных значений](#languages-php-types)
- [PHP: именование и границы PSR-1](#languages-php-naming)
- [PHP: namespace, PSR-4 и автозагрузка](#languages-php-autoload)

<a id="languages-go-naming"></a>

# Go: имена, экспорт и инициализмы

## Коротко

В Go имя определяет экспорт. Используйте MixedCaps/mixedCaps, согласованные ID/HTTP/URL и короткие lowercase package names.

## Плохо

```go
package BillingUtils

type invoice_data struct{ UserId string }
const MAX_ITEMS = 100
func Make_invoice(user_id string) invoice_data {
    return invoice_data{UserId: user_id}
}
```

## Хорошо

```go
package billing

// Invoice хранит идентификатор владельца счета.
type Invoice struct{ UserID string }

const maxItems = 100

func newInvoice(userID string) Invoice {
	return Invoice{UserID: userID}
}
```

## Почему

Заглавная первая буква экспортирует объявление package scope, поле или метод; это часть API, а не только оформление. Constants в Go используют те же MixedCaps/mixedCaps, а не Python-профиль UPPER_SNAKE_CASE. Единый регистр инициализмов позволяет последовательно искать UserID, ServeHTTP и URL.

## Когда применять

Для нового рукописного Go-кода. Package name — короткое содержательное слово в нижнем регистре без underscores; выбирайте billing.Invoice вместо billing.BillingInvoice. Имена переменных/неэкспортируемых функций начинаются со строчной, публичных типов/функций — с заглавной. Инициализм внутри имени сохраняет регистр: userID, HTTPClient; в начале неэкспортируемого имени допустимо urlValue.

Экспортируйте только нужный интерфейс пакета, добавляйте doc comments к публичным объявлениям. Короткие i/err/ctx оправданы локальным контекстом; широкая область требует более предметного имени. Правила не требуют вручную переписывать generated code или имена внешнего protocol/schema. Изменение экспортируемого имени либо JSON/DB-тега оценивается как изменение совместимости; переименование Go-поля не должно случайно менять wire contract.

gofmt обязателен для оформления, но не проверяет смысл имени/экспорта; naming-review остается отдельным. Пример показывает стиль, не полную модель счета.

## Как проверить

1. Новый package billing → компиляция и чтение внешним пакетом → Invoice/UserID доступны, newInvoice не экспортирован → compile fixtures.

2. Имена UserId, ServeHttp, MAX_ITEMS → review → исправлены в рукописном коде без переименования protocol field → diff.

3. Переименование существующего exported symbol → проверка клиентов → breaking change замечен или сохранен адаптер → consumer build.

## Человек

Определяет публичную поверхность пакетов и исключения совместимости.

## Агент

Применяет gofmt, проверяет initials и не расширяет экспорт только ради удобства примера.

## Источники

- [Go Code Review Comments: Initialisms, Mixed Caps, Package Names](https://go.dev/wiki/CodeReviewComments)
- [Effective Go: Names и Package names](https://go.dev/doc/effective_go)
- [Go Specification: Exported identifiers](https://go.dev/ref/spec)

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/go/rules/go-naming.md)

---

<a id="languages-go-imports"></a>

# Go: явные imports и границы пакета

## Коротко

Импортируйте пакет под его обычным именем и обращайтесь через qualifier. Стандартная библиотека идет первой группой; исключения для alias, dot и side-effect imports должны иметь причину.

## Плохо

```go
package greeting

import . "fmt"
import s "strings"

func Greeting(name string) string {
    return Sprintf("Hello, %s", s.TrimSpace(name))
}
```

## Хорошо

```go
package greeting

import (
	"fmt"
	"strings"
)

// Greeting возвращает приветствие без пробелов по краям имени.
func Greeting(name string) string {
	return fmt.Sprintf("Hello, %s", strings.TrimSpace(name))
}
```

## Почему

Qualifier показывает происхождение вызова. Import cycle запрещен самим Go; неиспользуемый обычный import тоже ошибка компиляции. Автоматическое добавление import не подтверждает, что выбран правильный модуль или что его init не имеет нежелательных эффектов.

## Когда применять

Для Go packages. Сначала stdlib, затем внешние/проектные группы с пустой строкой по принятому профилю. Alias используйте при конфликте имен или устойчивом обоснованном API-контексте, а не для сокращения каждого имени. Dot-import не используйте в обычном коде; узкое исключение возможно в внешнем test package, когда оно обосновано, но явный qualifier предпочтителен.

Blank import означает выполнение init/registration; используйте его в точке сборки приложения или нужном тесте с пояснением, например для регистрации driver. Он не должен быть способом скрыть unused import. Не запускайте неуправляемые сетевые операции/долгие фоновые процессы в init. При цикле зависимостей пересмотрите расположение общего контракта; не обходите проблему ручным копированием пакета.

gofmt форматирует исходник. goimports может добавлять/удалять imports и группировать их, если проект выбрал закрепленную версию инструмента; результат и изменение go.mod проверяются человеком. Сборка выполняется для поддерживаемых tags/platforms, поскольку разные файлы могут иметь разные imports.

## Как проверить

1. Обычный импорт fmt/strings → сборка → вызовы явно принадлежат пакетам, unused imports нет → go test/go vet.

2. Добавлен цикл A→B→A либо лишний import → сборка → ошибка обнаружена → compiler output.

3. Нужен side-effect driver либо alias-конфликт → review → назначение и точка регистрации понятны, startup остается управляемым → import/init review.

## Человек

Выбирает профиль группировки и допустимые side-effect imports.

## Агент

Проверяет происхождение пакета, цикл и init; использует formatter без слепого принятия нового модуля.

## Источники

- [Go Code Review Comments: Imports, Import Blank, Import Dot, Gofmt](https://go.dev/wiki/CodeReviewComments)
- [Go Specification: Import declarations и initialization](https://go.dev/ref/spec)

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/go/rules/go-imports.md)

---

<a id="languages-go-types"></a>

# Go: типы и проверка значений на границе

## Коротко

Выражайте устойчивую структуру данными struct и конкретными типами. Разные предметные идентификаторы при реальном риске смешения могут иметь отдельные defined types; тип не заменяет runtime-проверку входа.

## Плохо

```go
type UserID = string
type OrderID = string
// Оба alias остаются string: случайная подмена компилируется.
```

## Хорошо

```go
type UserID string
type OrderID string

type Assignment struct {
	OrderID OrderID
	OwnerID UserID
}
```

## Почему

Defined type отличается от underlying type; alias лишь дает прежнему типу другое имя. Compiler предотвращает часть случайных присваиваний, но явное преобразование и пустое значение остаются возможными. Для ID из JSON нужны отдельные проверки формата, существования и полномочий.

## Когда применять

Для Go domain/API boundaries. Конкретный struct предпочтителен map[string]any, если поля известны; any допустим для действительно открытой структуры с дальнейшим type switch/проверкой. Не создавайте interface без потребителя: маленький интерфейс описывает нужное поведение, а не зеркалирует все методы реализации. Для отсутствия/ошибки определите nil, ok или error явно, не смешивайте с допустимым нулем.

Учитывайте zero value: nil map читается, но запись требует инициализации; nil slice допускает append. Interface с typed nil pointer не равен nil interface — это важно при возврате error. Не утверждайте, что named integer автоматически ограничивает диапазон или overflow; размер int зависит от платформы, для wire/storage выберите явный контракт ширины/диапазона. Для длительности используйте time.Duration с единицами, для денег — отдельный точный профиль.

Generics вводятся для повторяющегося типобезопасного алгоритма, когда это упрощает потребителей; они не являются обязательным слоем каждого DTO. Возможности языка и синтаксис должны соответствовать go directive проекта. Пример — декларации внутри пакета, не законченный валидатор ID.

## Как проверить

1. Значения OrderID и UserID → обычное присваивание одному полю → корректный тип принимается, переменная другого defined type без conversion не компилируется → compile fixtures.

2. Пустой/неверный строковый ID проходит explicit conversion → boundary validator → отклонен по отдельному контракту → отрицательный runtime-тест проекта.

3. nil map/interface и нулевой числовой ввод → код соответствующей границы → нет неучтенного panic/ложного успеха, результат задокументирован → узкие edge tests.

## Человек

Определяет семантику типов, допустимые нулевые значения и границы валидации.

## Агент

Различает alias/defined type, проверяет nil и диапазоны; не подменяет runtime-проверку компиляцией.

## Источники

- [Go Specification: type declarations, assignability, zero values, maps/interfaces](https://go.dev/ref/spec)
- [Go Code Review Comments: Interfaces и In-Band Errors](https://go.dev/wiki/CodeReviewComments)
- [Go FAQ: typed nil внутри interface и error](https://go.dev/doc/faq#nil_error)

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/go/rules/go-types.md)

---

<a id="languages-go-toolchain"></a>

# Go: версия toolchain и граф модулей

## Коротко

У Go-проекта есть объявленный minimum Go version, выбранная toolchain для проверки и контролируемый граф модулей. go.sum не является полным lockfile и не фиксирует компилятор.

## Плохо

```text
go get -u ./... на каждой сборке.
Версия Go берется из latest; go.sum удаляется при конфликте.
Локальный replace ../shared попадает в release незаметно.
```

## Хорошо

```text
В среде с выбранной версией Go:
  go version
  go env GOTOOLCHAIN GOMOD
  go mod verify
  go test -mod=readonly ./...
  go vet ./...
Изменения go.mod/go.sum и toolchain проходят review отдельно от сборки.
```

## Почему

Начиная с Go 1.21 go directive задает минимальную версию, а toolchain/GOTOOLCHAIN влияют на фактически используемый compiler, включая автоматическое переключение. go.mod участвует в minimum version selection; go.sum хранит проверочные суммы, а не произвольное обещание зафиксировать все входы сборки.

## Когда применять

Для Go modules. Сохраняйте go.mod и нужный go.sum; при отсутствии внешних зависимостей пустой go.sum не требуется. Минимальная версия выбирается по используемому языку/API, фактическая CI/release toolchain и supported platforms фиксируются отдельно. Если automatic download toolchain разрешен, его политика и выбранная версия должны быть видны; при запрете несовместимая версия должна явно отказать.

После намеренного изменения зависимостей выполняйте tidy и review diff, проверяйте replace/exclude и роль go.work. Локальный workspace не должен скрывать отсутствующий или другой release module. Версии внешних generators/linters также фиксируются; не выполняйте update latest при каждой сборке. go mod verify обнаруживает изменения загруженного module cache, но не доказывает отсутствие уязвимостей/вредоносного кода и не заменяет supply-chain policy.

В примере команды выполняются в модуле приложения-потребителя. go test проверяет текущие build tags/platform; матрица поддерживаемых вариантов задается проектом. Race detector используется для relevant concurrent paths отдельно и не является доказательством отсутствия всех races. Старые toolchain обновляются по политике поддержки/исправлений, а не закрепляются навсегда.

## Как проверить

1. Чистая среда с выбранной toolchain → build/test → версии и module graph совпадают с объявленными, go.mod не меняется → вывод версии и diff.

2. Toolchain старше minimum при запрещенном switch → команда → явный отказ, а не незаметная подмена → stderr.

3. Локальный replace/workspace либо измененный cache → release check → неучтенный путь или integrity failure обнаружен → module graph/verify.

## Человек

Задает поддерживаемые версии/платформы и политику обновления toolchain/modules.

## Агент

Фиксирует фактическую версию и graph, проверяет tidy diff и не объявляет go.sum доказательством безопасной сборки.

## Источники

- [Go Toolchains: go/toolchain/GOTOOLCHAIN и minimum version](https://go.dev/doc/toolchain)
- [Go Modules Reference: MVS, go.mod/go.sum, tidy и verify](https://go.dev/ref/mod)

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/go/rules/go-toolchain.md)

---

<a id="languages-python-naming"></a>

# Python: имена классов, функций и констант

## Коротко

Используйте PascalCase для классов, snake_case для функций, методов, переменных и модулей, UPPER_SNAKE_CASE для констант модуля. Исключения совместимости должны быть явными.

## Плохо

```python
# ReportBuilder.py
maxRows = 100

class report_builder:
    def BuildReport(self, UserId):
        return f"report:{UserId}"
```

## Хорошо

```python
# report_builder.py
MAX_ROWS = 100


class ReportBuilder:
    def build_report(self, user_id: int) -> str:
        return f"report:{user_id}"
```

## Почему

Последовательный регистр сообщает роль имени без дополнительного соглашения на каждый модуль. Python не делает UPPER_SNAKE_CASE неизменяемым и не делает _name защищенным от доступа: это соглашения публичного интерфейса, а не security controls.

## Когда применять

Для нового рукописного Python-кода; PascalCase соответствует CapWords в PEP 8. Module file называется report_builder.py, пакет — коротким lowercase именем; слова в модуле разделяются underscore, когда это нужно. Для метода экземпляра первый параметр self, для classmethod — cls. Ошибки-классы имеют содержательное имя с Error, если обозначают ошибку.

Непубличные имена начинаются с одного underscore. Double underscore применяйте только для предотвращения коллизий наследования, не для «защиты секрета»; не изобретайте новые dunder names. Избегайте имен list/str/id, когда они скрывают нужный builtin; для keyword используйте ясный синоним или class_. Не превращайте все значения в константы: MAX_ROWS — соглашение для стабильного параметра модуля.

Generated code, внешние payload keys и обязательные framework callbacks сохраняют контракт. Уже опубликованный mixedCase API не переименовывается с поломкой клиентов только ради PEP 8: нужен адаптер/deprecation. Formatter обычно не переименовывает символы; naming проверяется отдельно выбранным linter/review.

## Как проверить

1. Новый модуль с классом/методом/константой → review/import → имена соответствуют ролям и модуль импортируется → AST/linter.

2. Класс вызван через прежнее публичное имя → план rename → потребитель сохранен адаптером либо изменение объявлено breaking → consumer test.

3. _internal и MAX_ROWS → проверка документации → не заявлены как запрет доступа или runtime immutability → review контракта.

## Человек

Утверждает публичные имена и исключения для совместимости.

## Агент

Применяет профиль PEP 8, сохраняет внешние имена и проверяет builtin shadowing.

## Источники

- [PEP 8: Naming Conventions, Class/Function/Variable/Module names, Constants](https://peps.python.org/pep-0008/)

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/python/rules/python-naming.md)

---

<a id="languages-python-imports"></a>

# Python: явные imports и управляемая инициализация

## Коротко

Imports явно показывают происхождение имен. Группируйте stdlib, third-party и проектные пакеты; импорт модуля не должен сам выполнять бизнес-операцию.

## Плохо

```python
from json import *
import pathlib, os

result = loads(pathlib.Path("orders.json").read_text())
# Чтение файла запускается при любом import этого модуля.
```

## Хорошо

```python
import json
from pathlib import Path


def read_json(path: Path) -> object:
    return json.loads(path.read_text(encoding="utf-8"))
```

## Почему

Wildcard скрывает источник имени и может незаметно изменить namespace. Python выполняет код модуля при загрузке; тяжелая инициализация, сеть или чтение обязательного файла на уровне модуля мешают тестам, CLI и повторному использованию. Явная функция отделяет импорт от запуска операции.

## Когда применять

Для библиотек и приложений Python. Обычные imports находятся после docstring и допустимых __future__ declarations, до констант/кода; группы разделяются пустой строкой. import os и import sys обычно отдельными строками, from module import A, B допустим. Absolute imports предпочтительны; явные relative imports внутри пакета разрешены, если сохраняют ясность.

Не используйте from module import * в обычном коде. Узкое исключение — намеренный re-export публичного API с контролем __all__; это не разрешение скрывать произвольные зависимости. Отложенный import внутри функции допустим для optional dependency, цикла, измеримого startup cost; причина и поведение при отсутствии зависимости должны быть понятны. Не исправляйте packaging ручным добавлением случайных путей в sys.path.

TYPE_CHECKING imports не существуют в runtime: учитывайте introspection framework и версию механизма annotations. Модуль и тесты запускаются в установленном package/предусмотренном entry point, а не только благодаря текущей рабочей директории. Пример читает JSON при вызове и возвращает object; валидация структуры выполняется отдельно.

## Как проверить

1. Импорт example module при отсутствующем orders.json → import → успешно без чтения файла/сети → isolated import test.

2. Явный вызов read_json с корректным UTF-8 JSON → операция → разобранное значение → fixture.

3. Optional dependency отсутствует или package запускается из другой cwd → предусмотренный путь → понятный отказ/неактивная функция без sys.path workaround → packaging test.

## Человек

Определяет публичные re-exports и допустимую initialization policy.

## Агент

Проверяет зависимости и import-time эффекты; не скрывает cycle случайным изменением sys.path.

## Источники

- [PEP 8: Imports и public interfaces](https://peps.python.org/pep-0008/)
- [Python 3.14 Reference, §5: module loading и execution](https://docs.python.org/3.14/reference/import.html)

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/python/rules/python-imports.md)

---

<a id="languages-python-types"></a>

# Python: аннотации и runtime-валидация

## Коротко

Аннотируйте устойчивые границы функций и проверяйте их выбранным type checker. Недоверенный ввод валидируется в runtime: аннотация int не проверяет значение сама.

## Плохо

```python
def require_quantity(value: int) -> int:
    return value

require_quantity("many")  # Runtime принимает строку несмотря на аннотацию.
```

## Хорошо

```python
def require_quantity(value: object) -> int:
    if not isinstance(value, int) or isinstance(value, bool):
        raise TypeError("quantity must be an integer")
    if value < 1:
        raise ValueError("quantity must be positive")
    return value
```

## Почему

Python не обеспечивает function/variable annotations при вызове. object требует уточнить тип до использования; Any отключает значимую часть статической проверки. Даже int может содержать отрицательное число, а bool является подтипом int, что важно для строгого числового API.

## Когда применять

Для нового Python-кода с общими/public/domain functions, DTO и взаимодействием модулей. Явно указывайте параметры и возвращаемое значение, включая -> None, когда результата нет. Локальные очевидные переменные можно оставлять на inference. Выбранный type checker, версия и строгость входят в профиль проекта; не утверждайте «типизировано» без реально выполняемой проверки.

None в допустимых значениях и отсутствие аргумента — разные вещи: int | None не задает default автоматически. Для коллекции укажите тип элементов, для известной структуры используйте dataclass/TypedDict/schema по задаче, а не неограниченный dict[str, Any]. TypedDict и cast не валидируют JSON в runtime. Динамические библиотеки могут требовать Any, stubs или Protocol: ограничьте такую границу и не распространяйте отключение проверки на весь модуль.

Синтаксис list[int] требует Python 3.9+, X | None — 3.10+, type Alias = ... — 3.12+; выбирайте совместимый с requires-python. Профиль внешнего DTO, coercion, unknown fields и missing/null раскрыт в backend.typed-boundaries. Пример специально принимает object и не преобразует строку/float/bool в количество.

## Как проверить

1. Целое 2 → require_quantity → возвращает int 2 → runtime unit scenario.

2. Строка, 2.0, True, None → require_quantity → TypeError; 0/-1 → ValueError → негативные runtime fixtures.

3. Внутренний consumer ожидает str, а получает результат int → выбранный type checker → ошибка до запуска; удаление optional default не скрыто аннотацией → static fixture.

## Человек

Задает границы типизации, строгость и политику преобразования внешних значений.

## Агент

Различает type checking и runtime validation, ограничивает Any и проверяет минимальную версию синтаксиса.

## Источники

- [Python typing: annotations не enforced runtime; Any/object, TypedDict, cast](https://docs.python.org/3.14/library/typing.html)

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/python/rules/python-types.md)

---

<a id="languages-python-toolchain"></a>

# Python: интерпретатор, окружение и зависимости

## Коротко

Проект объявляет поддерживаемый Python и способ восстановить зависимости в чистом окружении. Установка в случайный системный interpreter не является воспроизводимым запуском.

## Плохо

```bash
sudo pip install package
pip install --upgrade все-зависимости перед каждым release
Скопировать .venv с другого компьютера и не проверять версию Python.
```

## Хорошо

```bash
# Пример POSIX-профиля pip: выбранный Python уже установлен.
python -m venv .venv
.venv/bin/python -m pip install --require-hashes -r requirements.lock
.venv/bin/python -m pip check
# requirements.lock заранее содержит pins и hashes всех зависимостей.
```

## Почему

venv изолирует Python packages от базового окружения, но не фиксирует автоматически сам interpreter и системные библиотеки. requires-python описывает совместимость установки, а не точный patch/runtime image. Lock/resolution приложения и диапазоны зависимостей публикуемой библиотеки решают разные задачи.

## Когда применять

Для Python приложений и пакетов. Зафиксируйте поддерживаемый диапазон в pyproject.toml через requires-python, когда используется project metadata; точную CI/deploy версию и платформу храните в конфигурации окружения. Тестируйте заявленные версии, а не ставьте диапазон шире проверенного. Build backend, formatter, linter/type checker также имеют контролируемые версии.

Выберите один поддержанный workflow — pip с pin/hash requirements либо менеджер с документированным lock/sync. В pip-примере файл заранее сформирован для нужной платформы, включает транзитивные зависимости и hashes; обычный pip freeze без hashes не равен ему. Library metadata задает допустимые диапазоны, а тестовая/release среда фиксируется отдельно. pip check проверяет совместимость установленных dependency requirements, не безопасность и не поведение приложения.

.venv не коммитится и не переносится как release artifact: окружение пересоздается; на Windows используется соответствующий Scripts/python.exe. Установка выполняется через interpreter -m pip, чтобы не перепутать pip другой среды. Нативные extensions и внешние libraries требуют учета OS/architecture/toolchain. Обновление зависимостей проводится отдельным review и проверкой, а не незаметно при каждом запуске.

## Как проверить

1. Чистое окружение выбранной версии/платформы → sync/install → ожидаемые pins и успешный pip check → interpreter/package inventory.

2. Неверный hash/отсутствующий pin в hash-mode или несовместимый Python → установка → явный отказ → stderr без fallback на latest.

3. Заявлены несколько Python версий либо native extension → CI matrix → проверены поддерживаемые сочетания; неподдерживаемое исключено явно → результаты матрицы.

## Человек

Выбирает поддерживаемую матрицу и workflow обновления/восстановления среды.

## Агент

Проверяет interpreter и metadata, использует чистое окружение и не приравнивает pip check к тестам приложения.

## Источники

- [Python venv: изоляция, пересоздание, непереносимость окружения](https://docs.python.org/3.14/library/venv.html)
- [PyPA Writing pyproject.toml: requires-python и build metadata](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/)
- [pip Repeatable installs: pins, transitive requirements, hash checking](https://pip.pypa.io/en/stable/topics/repeatable-installs/)
- [pip check: совместимость установленных зависимостей и коды выхода](https://pip.pypa.io/en/stable/cli/pip_check/)

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/python/rules/python-toolchain.md)

---

<a id="languages-javascript-naming"></a>

# Имена в JavaScript и TypeScript

## Коротко

В принятом здесь соглашении JavaScript/TypeScript переменные, параметры, обычные функции и методы называются camelCase; классы, интерфейсы, type aliases и React-компоненты — PascalCase.

## Плохо

```typescript
type invoice_summary = { id: string };
export function Format_invoice(INVOICE: invoice_summary): string {
  return `Счет ${INVOICE.id}`;
}
```

## Хорошо

```typescript
export type InvoiceSummary = { id: string };
export function formatInvoice(invoice: InvoiceSummary): string {
  return `Счет ${invoice.id}`;
}
const currentInvoice: InvoiceSummary = { id: 'inv-7' };
export const invoiceLabel = formatInvoice(currentInvoice);
```

## Почему

Различимые категории и содержательные имена облегчают чтение без искусственных префиксов и несовместимой смены внешнего контракта.

## Когда применять

Для нового и изменяемого JS/TS-кода после принятия этого соглашения. Существующий согласованный стиль не требует массового переименования ради одной правки. Генерируемые имена и контракт SDK могут быть исключением; причина должна быть понятна.

### Подробные условия

Имя должно описывать назначение; сокращения внутри составного имени оформляй последовательно, например loadHttpConfig. Это соглашение проекта, не ограничение синтаксиса языка.

Не меняй имена внешнего JSON/API, заданные контрактом, ради локального стиля. При необходимости преобразуй их один раз на границе. Публичный экспорт переименовывается с учетом потребителей. Имена файлов определяются фреймворком или принятой структурой; PascalCase компонента не означает обязательный PascalCase каждого файла.

## Как проверить

- Новый обычный helper и type alias → проверить имена → formatInvoice и InvoiceSummary соответствуют разным категориям.
- Внешнее поле invoice_id → обработать DTO → контракт сохранен; локальное invoiceId появляется только через явное преобразование.
- Публичная функция переименована → проверить импорты/потребителей → совместимость сохранена или изменение мигрировано явно.

## Человек

Выбирает соглашение проекта и принимает стоимость публичного переименования.

## Агент

Проверяет назначение символа и контракты потребителей; не применяет механическую замену ко всем JSON-ключам и файлам.

## Источники

- [Google TypeScript Style Guide](https://google.github.io/styleguide/tsguide.html) — Naming and constants; источник соглашения, не требование языка.
- [React: Your First Component](https://react.dev/learn/your-first-component) — Component capitalization and top-level definitions.

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/typescript/rules/javascript-naming.md)

---

<a id="languages-bindings"></a>

# Привязки const и let

## Коротко

Используй const для привязки, которую не переназначают, и let для действительного переназначения.

## Плохо

```javascript
export function renameUser(user) {
  const CURRENT_USER = user; // имя выбрано только из-за const
  CURRENT_USER.name = 'Новое имя'; // объект вызывающего кода изменен
  return CURRENT_USER;
}
```

## Хорошо

```javascript
export const DEFAULT_TIMEOUT_MS = 5000;
export function renameUser(user, name) {
  const updatedUser = { ...user, name };
  return updatedUser;
}
```

## Почему

Привязка, семантическая константа и неизменяемые данные — разные свойства. Их смешение скрывает мутацию и создает бессмысленный UPPERCASE.

## Когда применять

Для JS/TS. Пример показывает копирование верхнего уровня и не гарантирует независимость вложенных объектов. Для горячего алгоритма допустима контролируемая мутация принадлежащих ему данных; правило не требует всегда копировать все структуры.

### Подробные условия

const не делает объект или массив неизменяемым: их свойства могут меняться. Если нужна неизменяемость, выбери соответствующий контракт владения, readonly-проверку типов или runtime-защиту с учетом ее глубины; не обещай deep immutability от одного ключевого слова.

Обычная const-переменная остается camelCase. UPPER_SNAKE_CASE допускается для именованных констант уровня модуля с устойчивым значением/назначением по соглашению проекта, например DEFAULT_TIMEOUT_MS. Полученный пользователь, результат запроса и callback не становятся такой константой только из-за const.

## Как проверить

- Привязка не переназначается → объявить → const с обычным camelCase.
- Переименовать пользователя через пример → сравнить → возвращен новый объект, исходное name сохранено.
- В объекте есть вложенный объект → изменить его после shallow copy → обнаружена общая ссылка; deep immutability не заявлена.

## Человек

Определяет владение данными и область допустимой мутации.

## Агент

Отделяет запрет переназначения от неизменяемости объекта и не делает все const-имена прописными.

## Источники

- [TypeScript Handbook: Variable Declarations](https://www.typescriptlang.org/docs/handbook/variable-declarations.html) — let, const and binding versus object mutation.
- [Google TypeScript Style Guide](https://google.github.io/styleguide/tsguide.html) — Naming and constants; источник соглашения, не требование языка.

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/typescript/rules/bindings.md)

---

<a id="languages-runtime-boundaries"></a>

# Проверка внешних данных в TypeScript

## Коротко

Данные из JSON, storage, URL, формы и внешнего SDK проверь во время выполнения там, где они становятся входом доверенной логики.

## Плохо

```typescript
type UserDto = { id: string; displayName: string };
export function decodeUser(value: unknown): UserDto {
  return value as UserDto;
}
```

## Хорошо

```typescript
export type UserDto = { id: string; displayName: string };
export function decodeUser(value: unknown): UserDto {
  if (typeof value !== 'object' || value === null || Array.isArray(value)
    || !('id' in value) || typeof value.id !== 'string' || value.id.length === 0
    || !('displayName' in value) || typeof value.displayName !== 'string') {
    throw new TypeError('Invalid UserDto');
  }
  return { id: value.id, displayName: value.displayName };
}
```

## Почему

Типы исчезают при исполнении JavaScript. Проверка на границе предотвращает ложную уверенность в недоверенном объекте.

## Когда применять

Для TS-кода с внешними данными. Пример относится к уже разобранному JSON, допускает пустое displayName и игнорирует лишние поля; это его локальный контракт. Проверка синтаксиса JSON, лимит размера и авторизация остаются отдельными задачами. Повторно валидировать каждый внутренний вызов после установленной границы не требуется.

### Подробные условия

До проверки используй unknown, затем декодируй по нужному контракту. Assertion `as T`, generic у fetch-клиента и interface не проверяют фактическое значение.

Определи требуемые поля, допустимые значения, null/отсутствие и политику неизвестных полей. Возвращай только нужный внутренний DTO. Для простой формы достаточно явных guards; schema-библиотека оправдана повторным использованием/сложностью, а не самим TypeScript. Ошибка декодирования должна иметь контролируемый результат без раскрытия всего чувствительного payload.

## Как проверить

- Объект с корректными полями и лишним полем → decode → возвращены только id/displayName.
- null, массив, пустой id или неверный тип displayName → decode → TypeError без печати payload.
- displayName пустой, id непустой → decode → успех согласно явно разрешенному контракту.

## Человек

Определяет фактический контракт внешних данных и реакцию на его нарушение.

## Агент

Проверяет guards на отрицательных и граничных значениях; не заменяет декодирование assertion.

## Источники

- [TypeScript Handbook: Narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) — Runtime guards, control flow and discriminated unions.

Уровень: Обязательно. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/typescript/rules/runtime-boundaries.md)

---

<a id="languages-nullability"></a>

# Отсутствие, null и undefined

## Коротко

В TypeScript-проекте используй проверку null/undefined (`strictNullChecks`) и опиши их семантику в контракте.

## Плохо

```typescript
export function applyNickname(current: string | null, patch: { nickname?: string | null }) {
  return patch.nickname || current; // null и пустая строка потеряли смысл
}
```

## Хорошо

```typescript
export type NicknamePatch = { nickname?: string | null };
export function applyNickname(current: string | null, patch: NicknamePatch): string | null {
  if (!Object.hasOwn(patch, 'nickname')) return current;
  if (patch.nickname === null || typeof patch.nickname === 'string') return patch.nickname;
  throw new TypeError('nickname must be a string or null');
}
```

## Почему

Явная семантика сохраняет намерение клиента: не менять поле, очистить его или записать допустимое пустое значение.

## Когда применять

Для TypeScript с совместимыми настройками компилятора. В примере: отсутствие — оставить, null — очистить, строка включая пустую — заменить, явный undefined — ошибка. Это проектный PATCH-контракт, не универсальное поведение всех API. Object.hasOwn требует подходящей runtime/lib-версии (ES2022).

### Подробные условия

Отсутствующее необязательное поле, null, пустая строка, 0 и false не взаимозаменяемы. `||` подменяет все falsy-значения; `??` — только null/undefined. Выбирай оператор по семантике, а не по краткости.

Non-null assertion `!` не добавляет runtime-проверку. Применяй его только при доказанном инварианте; при внешнем входе сначала нужен guard. Если различие между отсутствием optional-поля и явным undefined значимо, проверь настройки типов (в том числе exactOptionalPropertyTypes), сериализацию и runtime-контракт.

## Как проверить

- Поле отсутствует → applyNickname → текущее значение сохранено.
- nickname=null либо пустая строка → применить → очистка либо пустая строка различаются и сохраняются.
- nickname присутствует с undefined/неверным типом → применить → TypeError; настройка компилятора не выдается за runtime-защиту.

## Человек

Определяет различия отсутствия, очистки и пустого значения для конкретного поля.

## Агент

Проверяет compiler options и сериализацию; не применяет !/||, чтобы скрыть неразобранный контракт.

## Источники

- [TypeScript: strictNullChecks](https://www.typescriptlang.org/tsconfig/strictNullChecks.html) — Null and undefined as distinct types when enabled.
- [TypeScript Handbook: Narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) — Runtime guards, control flow and discriminated unions.

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/typescript/rules/nullability.md)

---

<a id="languages-promise-errors"></a>

# Результаты и ошибки Promise

## Коротко

У каждой асинхронной операции должен быть владелец результата: await, возврат Promise вызывающему коду или явный обработчик отказа у фоновой операции.

## Плохо

```typescript
export function startSave(save: () => Promise<void>): string {
  void save();
  return 'saved';
}
```

## Хорошо

```typescript
export type SaveResult = { status: 'saved' } | { status: 'failed'; cause: unknown };
export async function saveWithResult(save: () => Promise<void>): Promise<SaveResult> {
  try {
    await save();
    return { status: 'saved' };
  } catch (cause: unknown) {
    return { status: 'failed', cause };
  }
}
```

## Почему

Отложенный отказ не должен становиться ложным сообщением об успехе или неуправляемой ошибкой процесса.

## Когда применять

Для JS/TS Promise API. Пример возвращает внутренний результат; вызывающий код обязан разобрать status, а cause нельзя без очистки выводить пользователю или в журнал. Допустима и передача rejected Promise вызывающему слою, если там явно определен обработчик. Это правило не требует превращать каждую ошибку в Result-объект.

### Подробные условия

Успех показывается после подтвержденного результата. `void promise` только отбрасывает значение; rejection остается необработанным, если никто его не принимает.

Обработчик различает отказ и успех и выполняет нужное освобождение ресурсов. Не скрывай ошибку пустым catch. Для deliberate background operation обоснуй, почему завершение вызывающей функции допустимо раньше, кто обрабатывает отказ и что происходит при завершении процесса. Линтер no-floating-promises помогает найти пропуск, но его настройки не доказывают runtime-корректность.

## Как проверить

- save выполняется успешно с задержкой → await saveWithResult → saved появляется только после завершения.
- save отклоняет Promise → дождаться результата → failed с cause, ложного saved нет.
- Фоновый вызов помечен void → проверить путь отказа и завершение процесса → один void не считается обработкой или гарантией доставки.

## Человек

Определяет допустимую фоновую работу и видимый результат отказа.

## Агент

Проверяет владельца каждого Promise, различает deliberate background и забытый await; не подавляет предупреждение без обработки.

## Источники

- [typescript-eslint: no-floating-promises](https://typescript-eslint.io/rules/no-floating-promises/) — Handled promises; void does not handle rejection.

Уровень: Обязательно. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/typescript/rules/promise-errors.md)

---

<a id="languages-module-boundaries"></a>

# Модули и разрешение импортов

## Коротко

Определи публичные экспорты модуля и разрешенное направление зависимостей; внутренние файлы не становятся стабильным API по факту доступности пути.

## Плохо

```text
TypeScript принимает alias @internal/db.
Его runtime-поддержка не настроена; браузер импортирует Node-only пакет.
Импорт типа считается гарантией выполнения регистрации модуля.
```

## Хорошо

```text
Контракт: публичный export модели; внутренний путь не обещан потребителю.
Node ESM со сборкой: выбран совместимый moduleResolution и runtime specifier.
Type-only зависимость: import type; side effect, если нужен, импортирован явно.
Проверка: чистая сборка и запуск разрешенного entrypoint в целевой среде.
Browser entrypoint не включает server-only зависимость.
```

## Почему

Компилятор, bundler и runtime решают разные задачи. Несогласованное разрешение импортов может пройти проверку типов и отказать только после выпуска.

## Когда применять

Для JS/TS модулей и пакетов. Расширения и правила ESM/CommonJS зависят от runtime и сборки; не навязывай один режим браузеру, Node и тестовому runner. Пример описывает контракт проверки, а не готовую конфигурацию.

### Подробные условия

Не создавай слой или barrel-файл без задачи: сокрытие реализации, совместимость либо повторное использование.

Согласуй module/moduleResolution, package type, расширения импортов и bundler с фактическим runtime. Успешный typecheck не гарантирует, что модуль найдется при исполнении. paths в tsconfig сам по себе не переписывает emitted imports. Для импорта только типов используй import type, если это соответствует toolchain; он не должен неявно обеспечивать нужный side effect. Серверные зависимости не импортируются в браузерный модуль.

## Как проверить

- Публичный entrypoint → собрать и запустить в целевой среде → зависимости разрешены без скрытого local alias.
- Alias известен только tsconfig → выполнить runtime-проверку → проблема выявлена до выпуска.
- Type-only import удален при сборке, а регистрация нужна → проверить → side effect импортирован отдельно либо архитектура исправлена.

## Человек

Определяет публичную границу и поддерживаемые runtime/toolchain.

## Агент

Проверяет реальный запуск entrypoint и граф зависимостей, не маскирует runtime-ошибку дополнительным assertion.

## Источники

- [TypeScript: Modules Reference](https://www.typescriptlang.org/docs/handbook/modules/reference.html) — Type-only imports, module resolution, paths and emitted specifiers.
- [Next.js App Router: Server and Client Components](https://nextjs.org/docs/app/getting-started/server-and-client-components) — Client module graph, serializable props and server-only modules.

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/typescript/rules/module-boundaries.md)

---

<a id="languages-php-types"></a>

# PHP: типы и проверка входных значений

## Коротко

В новом PHP-коде описывайте типы параметров, возврата и свойств, а на внешней границе отдельно проверяйте значение. strict_types и тип int не заменяют проверку положительного количества или допустимого ID.

## Плохо

```php
function quantity($value) {
    return (int) $value; // "12items" становится 12, null становится 0.
}
$count = quantity($request['quantity']);
```

## Хорошо

```php
<?php
declare(strict_types=1);

namespace Project\Order;

function requireQuantity(mixed $value): int
{
    if (!is_int($value) || $value < 1) {
        throw new \InvalidArgumentException('quantity must be a positive integer');
    }
    return $value;
}
// Для JSON-контракта: requireQuantity(3) -> 3.
// Строка "3", null, float и массив отвергаются без приведения.
```

## Почему

Native-типы ловят несоответствие формы данных, а доменная проверка ограничивает их смысл. Приведение до проверки может скрыть исходную ошибку. Nullable-тип разрешает null, но не говорит, что поле запроса можно не передавать.

## Когда применять

Baseline примера — PHP 8.2+, JSON quantity целого типа. `declare(strict_types=1)` включается по файлам для нового контролируемого кода; для скалярных аргументов режим определяется вызывающим файлом. Один strict-файл не переводит весь legacy-проект в строгий режим, а внутренние PHP-вызовы имеют свои особенности.

HTML/query обычно дают строки: если контракт их допускает, разбирайте их явно с проверкой формата, диапазона PHP_INT_MAX и нужных ограничений. Это иной адаптер, а не повод делать `mixed` во всей бизнес-логике. После адаптера используйте конкретный тип или небольшой объект значения.

Типы массивов PHP не проверяют форму каждого элемента; где нужна структура, добавьте DTO/валидацию и документируйте shape для анализатора. Не принимайте docblock за runtime validation. Выбирайте nullable/union по реальным исходам; не добавляйте `false|null|array` только ради сокрытия ошибок.

Сигнатуры переопределенных методов, hook/callback и публичного API меняйте с учетом совместимости. PHP-язык не требует PSR naming; WordPress и Bitrix legacy не обязаны автоматически получить новые сигнатуры.

## Как проверить

| Вход и действие | Ожидаемый результат | Свидетельство |
| --- | --- | --- |
| requireQuantity(3) | Возвращает int 3 | Unit-тест на baseline PHP |
| 0, -1, "3", "12items", null, 3.5, массив | Каждый отвергнут до бизнес-операции | Таблица случаев |
| Строковый HTTP-адаптер с числом больше PHP_INT_MAX | Явный отказ без переполнения/усечения | Граничный тест адаптера |
| Вызов typed-функции из strict и non-strict файлов | Зафиксировано различие coercion; политика не полагается на один callee-файл | Два отдельных файла теста |
| Изменена сигнатура legacy hook | Сохранен контракт всех вызывающих сторон | Проверка интеграции с платформой |

Эти сценарии предназначены приложению; PHP runtime в редакционной среде отсутствует.

## Человек

Утверждает входные форматы и политику совместимости legacy-кода.

## Агент

Разделяет типизацию и валидацию, сверяет минимальную версию PHP и вызывающую сторону strict_types.

## Источники

- [PHP: type declarations](https://www.php.net/manual/en/language.types.declarations.php)
- [PHP: integers](https://www.php.net/manual/en/language.types.integer.php)

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/php/rules/php-types.md)

---

<a id="languages-php-naming"></a>

# PHP: именование и границы PSR-1

## Коротко

Для нового PHP-пакета выберите именование и применяйте его последовательно. PSR-1 задает имена классов, методов и констант, но это соглашение совместимости, а не синтаксическое требование PHP.

## Плохо

```php
namespace Project\Order;
class order_service {
    public const retryLimit = 3;
    public function Get_order($Order_ID) { /* ... */ }
}
```

## Хорошо

```php
<?php
namespace Project\Order;

final class OrderService
{
    public const RETRY_LIMIT = 3;

    public function formatOrderId(int $orderId): string
    {
        return 'order-' . $orderId;
    }
}
```

## Почему

Предсказуемое имя помогает искать определение и отличать класс от метода или константы. Единый стиль облегчает автозагрузку и чтение, но массовое переименование публичного API может сломать пользователей без изменения поведения.

## Когда применять

Новый код, для которого проект принял PSR-1: классы `StudlyCaps`, методы `camelCase`, константы класса `UPPER_SNAKE_CASE`. Для переменных и свойств пример выбирает `camelCase` как соглашение проекта: PSR-1 намеренно не навязывает стиль свойств.

Имена отражают назначение: `OrderService` и `formatOrderId`, а не случайные сокращения. Уточняйте единицы и смысл там, где они важны, например `timeoutSeconds`. Выбор английских идентификаторов и доменных терминов фиксируется командой; это не ограничение языка.

Для WordPress применяйте его coding standards и префиксы/namespace плагина. В Bitrix сохраняйте контрактные имена классического API, установщика, событий и существующих расширений. Новый изолированный PSR-пакет может жить рядом с legacy через адаптер; глобальное переименование старых hooks или методов из этого правила не следует.

Файл объявления класса не должен сам выводить HTML, создавать соединение или запускать импорт. Bootstrap платформы и исполняемая точка входа отделяются от объявления; PSR-1 формулирует это как SHOULD, а шаблон с PHP/HTML имеет другой контекст.

## Как проверить

| Вход и действие | Ожидаемый результат | Свидетельство |
| --- | --- | --- |
| Новый класс/метод/константа в PSR-пакете | Соответствуют принятому стилю и назначению | Diff и настроенный ruleset приложения |
| Свойство camelCase, которое анализатор ошибочно считает не-PSR | Нет ложного требования от PSR-1; применяется локальное соглашение | Конфигурация проверки |
| Адаптер к legacy hook/классу WordPress или Bitrix | Контрактное имя сохранено | Интеграционный вызов |
| Autoload класса без вызова методов | Нет вывода и внешнего I/O | Проверка подключения файла |

Стиль не измеряется числом исправленных имен; публичные переименования требуют отдельной миграции.

## Человек

Выбирает стандарт именования по границам пакета и владеет словарем домена.

## Агент

Не выдает предпочтения проекта за требования PHP/PSR; сохраняет публичные legacy-имена.

## Источники

- [PHP-FIG: PSR-1](https://www.php-fig.org/psr/psr-1/)
- [WordPress: PHP coding standards](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/)

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/php/rules/php-naming.md)

---

<a id="languages-php-autoload"></a>

# PHP: namespace, PSR-4 и автозагрузка

## Коротко

Свяжите namespace с путями через явную конфигурацию загрузчика. Для нового Composer-пакета предпочитайте PSR-4 и точное совпадение регистра; use импортирует имя, а не файл.

## Плохо

```text
Класс Acme\Billing\Invoice лежит в src/invoice.php.
use Acme\Billing\Invoice считается подключением файла.
В каждом endpoint вручную требуют разные копии Invoice.php.
```

## Хорошо

```json
{
  "autoload": {
    "psr-4": {
      "Acme\\Billing\\": "src/"
    }
  }
}
```

## Почему

Единая карта загрузки убирает зависимость от порядка ручных require. Ошибка регистра может оставаться незаметной на рабочей машине и проявиться на Linux. Namespace сам по себе не создает автозагрузку.

## Когда применять

Composer 2 и новый PHP-пакет с PSR-4. При показанной карте `Acme\Billing\Invoice` объявляется в `src/Invoice.php`, а `Acme\Billing\Service\InvoiceSender` — в `src/Service/InvoiceSender.php`. Префикс заканчивается обратным слешем; путь считается от корня пакета. Каждый сегмент пути и имя класса согласованы по регистру.

Bootstrap подключает сгенерированный `vendor/autoload.php` один раз. После изменения конфигурации/оптимизированной classmap пересоберите autoload штатной командой Composer; файлы vendor не редактируют вручную. Классы тестов размещают в autoload-dev, чтобы production-код не зависел от dev-пакетов.

PSR-4 относится к классоподобным сущностям и не автозагружает произвольную функцию по `use function`. Для функций/legacy доступны явно выбранные files/classmap или платформенный loader; их side effects должны быть понятны.

Bitrix Loader и WordPress bootstrap — другие контексты. Не утверждайте, что старый D7 с lowercase lib полностью совпадает с PSR-4, и не добавляйте параллельный loader для тех же классов без необходимости. Переезд имени/пути публичного класса требует плана совместимости.

## Как проверить

| Вход и действие | Ожидаемый результат | Свидетельство |
| --- | --- | --- |
| Чистая установка production-зависимостей, первый вызов Invoice | Класс найден без ручных require | Проверка в case-sensitive файловой системе |
| Файл назван invoice.php вместо Invoice.php | Несоответствие обнаружено до выпуска | Проверка карты и сборки |
| Изменен namespace prefix или optimized classmap | После штатной пересборки все точки входа видят один класс | Smoke-тест HTTP/CLI/worker |
| Production-класс ссылается на autoload-dev | Проверка --no-dev выявляет нарушение | Запуск с production-зависимостями |

JSON примера является фрагментом composer.json приложения, а не исполняемым файлом этого репозитория стандартов.

## Человек

Определяет границу пакета и допустимый переход legacy-имен.

## Агент

Сверяет prefix, namespace, регистр и bootstrap на всех точках входа. Не считает use механизмом загрузки.

## Источники

- [PHP-FIG: PSR-4](https://www.php-fig.org/psr/psr-4/)
- [Composer: schema autoload](https://getcomposer.org/doc/04-schema.md#autoload)
- [PHP: autoloading classes](https://www.php.net/manual/en/language.oop5.autoload.php)

Уровень: Рекомендуется. Опубликовано: 2026-11-13. Проверено: 2026-11-13. Изменено: 2026-11-13.

[Исходный файл](https://github.com/sergey-from-riders/vibecoding-base/blob/d33454c0dad753475ecc92aaecf8d783f02fd01b/registry/standards/languages/php/rules/php-autoload.md)
